]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/duktape-1.8.0/src/duktape.c
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / third_party / duktape-1.8.0 / src / duktape.c
CommitLineData
1e59de90
TL
1/*
2 * Single source autogenerated distributable for Duktape 1.8.0.
3 *
4 * Git commit 0a70d7e4c5227c84e3fed5209828973117d02849 (v1.8.0).
5 * Git branch v1.8-maintenance.
6 *
7 * See Duktape AUTHORS.rst and LICENSE.txt for copyright and
8 * licensing information.
9 */
10
11/* LICENSE.txt */
12/*
13* ===============
14* Duktape license
15* ===============
16*
17* (http://opensource.org/licenses/MIT)
18*
19* Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
20*
21* Permission is hereby granted, free of charge, to any person obtaining a copy
22* of this software and associated documentation files (the "Software"), to deal
23* in the Software without restriction, including without limitation the rights
24* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25* copies of the Software, and to permit persons to whom the Software is
26* furnished to do so, subject to the following conditions:
27*
28* The above copyright notice and this permission notice shall be included in
29* all copies or substantial portions of the Software.
30*
31* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37* THE SOFTWARE.
38*/
39/* 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>
69* * Ren\u00e9 Hollander <rene@rene8888.at>
70* * Julien Hamaide (https://github.com/crazyjul)
71* * Sebastian G\u00f6tte (https://github.com/jaseg)
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
108* * Laurent Zubiaur (https://github.com/lzubiaur)
109* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
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*/
114#line 1 "duk_internal.h"
115/*
116 * Top-level include file to be used for all (internal) source files.
117 *
118 * Source files should not include individual header files, as they
119 * have not been designed to be individually included.
120 */
121
122#ifndef DUK_INTERNAL_H_INCLUDED
123#define DUK_INTERNAL_H_INCLUDED
124
125/*
126 * The 'duktape.h' header provides the public API, but also handles all
127 * compiler and platform specific feature detection, Duktape feature
128 * resolution, inclusion of system headers, etc. These have been merged
129 * because the public API is also dependent on e.g. detecting appropriate
130 * C types which is quite platform/compiler specific especially for a non-C99
131 * build. The public API is also dependent on the resolved feature set.
132 *
133 * Some actions taken by the merged header (such as including system headers)
134 * are not appropriate for building a user application. The define
135 * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some
136 * sections depending on what is being built.
137 */
138
139#define DUK_COMPILING_DUKTAPE
140#include "duktape.h"
141
142/*
143 * User declarations, e.g. prototypes for user functions used by Duktape
144 * macros. Concretely, if DUK_USE_PANIC_HANDLER is used and the macro
145 * value calls a user function, it needs to be declared for Duktape
146 * compilation to avoid warnings.
147 */
148
149DUK_USE_USER_DECLARE()
150
151/*
152 * Duktape includes (other than duk_features.h)
153 *
154 * The header files expect to be included in an order which satisfies header
155 * dependencies correctly (the headers themselves don't include any other
156 * includes). Forward declarations are used to break circular struct/typedef
157 * dependencies.
158 */
159
160#line 1 "duk_replacements.h"
161#ifndef DUK_REPLACEMENTS_H_INCLUDED
162#define DUK_REPLACEMENTS_H_INCLUDED
163
164#if !defined(DUK_SINGLE_FILE)
165#if defined(DUK_USE_COMPUTED_INFINITY)
166DUK_INTERNAL_DECL double duk_computed_infinity;
167#endif
168#if defined(DUK_USE_COMPUTED_NAN)
169DUK_INTERNAL_DECL double duk_computed_nan;
170#endif
171#if defined(DUK_USE_REPL_FPCLASSIFY)
172DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
173#endif
174#if defined(DUK_USE_REPL_SIGNBIT)
175DUK_INTERNAL_DECL int duk_repl_signbit(double x);
176#endif
177#if defined(DUK_USE_REPL_ISFINITE)
178DUK_INTERNAL_DECL int duk_repl_isfinite(double x);
179#endif
180#if defined(DUK_USE_REPL_ISNAN)
181DUK_INTERNAL_DECL int duk_repl_isnan(double x);
182#endif
183#if defined(DUK_USE_REPL_ISINF)
184DUK_INTERNAL_DECL int duk_repl_isinf(double x);
185#endif
186#endif /* !DUK_SINGLE_FILE */
187
188#endif /* DUK_REPLACEMENTS_H_INCLUDED */
189#line 1 "duk_jmpbuf.h"
190/*
191 * Wrapper for jmp_buf.
192 *
193 * This is used because jmp_buf is an array type for backward compatibility.
194 * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc,
195 * behave more intuitively.
196 *
197 * http://en.wikipedia.org/wiki/Setjmp.h#Member_types
198 */
199
200#ifndef DUK_JMPBUF_H_INCLUDED
201#define DUK_JMPBUF_H_INCLUDED
202
203#if defined(DUK_USE_CPP_EXCEPTIONS)
204struct duk_jmpbuf {
205 duk_small_int_t dummy; /* unused */
206};
207#else
208struct duk_jmpbuf {
209 DUK_JMPBUF_TYPE jb;
210};
211#endif
212
213#endif /* DUK_JMPBUF_H_INCLUDED */
214#line 1 "duk_exception.h"
215/*
216 * Exception for Duktape internal throws when C++ exceptions are used
217 * for long control transfers.
218 *
219 * Doesn't inherit from any exception base class to minimize the chance
220 * that user code would accidentally catch this exception.
221 */
222
223#ifndef DUK_EXCEPTION_H_INCLUDED
224#define DUK_EXCEPTION_H_INCLUDED
225
226#if defined(DUK_USE_CPP_EXCEPTIONS)
227class duk_internal_exception {
228 /* intentionally empty */
229};
230#endif
231
232#endif /* DUK_EXCEPTION_H_INCLUDED */
233#line 1 "duk_forwdecl.h"
234/*
235 * Forward declarations for all Duktape structures.
236 */
237
238#ifndef DUK_FORWDECL_H_INCLUDED
239#define DUK_FORWDECL_H_INCLUDED
240
241/*
242 * Forward declarations
243 */
244
245#if defined(DUK_USE_CPP_EXCEPTIONS)
246class duk_internal_exception;
247#else
248struct duk_jmpbuf;
249#endif
250
251/* duk_tval intentionally skipped */
252struct duk_heaphdr;
253struct duk_heaphdr_string;
254struct duk_hstring;
255struct duk_hstring_external;
256struct duk_hobject;
257struct duk_hcompiledfunction;
258struct duk_hnativefunction;
259struct duk_hthread;
260struct duk_hbufferobject;
261struct duk_hbuffer;
262struct duk_hbuffer_fixed;
263struct duk_hbuffer_dynamic;
264struct duk_hbuffer_external;
265
266struct duk_propaccessor;
267union duk_propvalue;
268struct duk_propdesc;
269
270struct duk_heap;
271struct duk_breakpoint;
272
273struct duk_activation;
274struct duk_catcher;
275struct duk_strcache;
276struct duk_ljstate;
277struct duk_strtab_entry;
278
279#ifdef DUK_USE_DEBUG
280struct duk_fixedbuffer;
281#endif
282
283struct duk_bitdecoder_ctx;
284struct duk_bitencoder_ctx;
285struct duk_bufwriter_ctx;
286
287struct duk_token;
288struct duk_re_token;
289struct duk_lexer_point;
290struct duk_lexer_ctx;
291struct duk_lexer_codepoint;
292
293struct duk_compiler_instr;
294struct duk_compiler_func;
295struct duk_compiler_ctx;
296
297struct duk_re_matcher_ctx;
298struct duk_re_compiler_ctx;
299
300#if defined(DUK_USE_CPP_EXCEPTIONS)
301/* no typedef */
302#else
303typedef struct duk_jmpbuf duk_jmpbuf;
304#endif
305
306/* duk_tval intentionally skipped */
307typedef struct duk_heaphdr duk_heaphdr;
308typedef struct duk_heaphdr_string duk_heaphdr_string;
309typedef struct duk_hstring duk_hstring;
310typedef struct duk_hstring_external duk_hstring_external;
311typedef struct duk_hobject duk_hobject;
312typedef struct duk_hcompiledfunction duk_hcompiledfunction;
313typedef struct duk_hnativefunction duk_hnativefunction;
314typedef struct duk_hbufferobject duk_hbufferobject;
315typedef struct duk_hthread duk_hthread;
316typedef struct duk_hbuffer duk_hbuffer;
317typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
318typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
319typedef struct duk_hbuffer_external duk_hbuffer_external;
320
321typedef struct duk_propaccessor duk_propaccessor;
322typedef union duk_propvalue duk_propvalue;
323typedef struct duk_propdesc duk_propdesc;
324
325typedef struct duk_heap duk_heap;
326typedef struct duk_breakpoint duk_breakpoint;
327
328typedef struct duk_activation duk_activation;
329typedef struct duk_catcher duk_catcher;
330typedef struct duk_strcache duk_strcache;
331typedef struct duk_ljstate duk_ljstate;
332typedef struct duk_strtab_entry duk_strtab_entry;
333
334#ifdef DUK_USE_DEBUG
335typedef struct duk_fixedbuffer duk_fixedbuffer;
336#endif
337
338typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx;
339typedef struct duk_bitencoder_ctx duk_bitencoder_ctx;
340typedef struct duk_bufwriter_ctx duk_bufwriter_ctx;
341
342typedef struct duk_token duk_token;
343typedef struct duk_re_token duk_re_token;
344typedef struct duk_lexer_point duk_lexer_point;
345typedef struct duk_lexer_ctx duk_lexer_ctx;
346typedef struct duk_lexer_codepoint duk_lexer_codepoint;
347
348typedef struct duk_compiler_instr duk_compiler_instr;
349typedef struct duk_compiler_func duk_compiler_func;
350typedef struct duk_compiler_ctx duk_compiler_ctx;
351
352typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
353typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
354
355#endif /* DUK_FORWDECL_H_INCLUDED */
356#line 1 "duk_tval.h"
357/*
358 * Tagged type definition (duk_tval) and accessor macros.
359 *
360 * Access all fields through the accessor macros, as the representation
361 * is quite tricky.
362 *
363 * There are two packed type alternatives: an 8-byte representation
364 * based on an IEEE double (preferred for compactness), and a 12-byte
365 * representation (portability). The latter is needed also in e.g.
366 * 64-bit environments (it usually pads to 16 bytes per value).
367 *
368 * Selecting the tagged type format involves many trade-offs (memory
369 * use, size and performance of generated code, portability, etc),
370 * see doc/types.rst for a detailed discussion (especially of how the
371 * IEEE double format is used to pack tagged values).
372 *
373 * NB: because macro arguments are often expressions, macros should
374 * avoid evaluating their argument more than once.
375 */
376
377#ifndef DUK_TVAL_H_INCLUDED
378#define DUK_TVAL_H_INCLUDED
379
380/* sanity */
381#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
382#error unsupported: cannot determine byte order variant
383#endif
384
385#if defined(DUK_USE_PACKED_TVAL)
386/* ======================================================================== */
387
388/*
389 * Packed 8-byte representation
390 */
391
392/* use duk_double_union as duk_tval directly */
393typedef union duk_double_union duk_tval;
394
395/* tags */
396#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
397/* avoid tag 0xfff0, no risk of confusion with negative infinity */
398#if defined(DUK_USE_FASTINT)
399#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
400#endif
401#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */
402#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */
403#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */
404#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */
405/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
406#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */
407#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */
408#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
409#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
410#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
411
412/* for convenience */
413#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
414#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
415
416/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
417#if defined(DUK_USE_64BIT_OPS)
418#if defined(DUK_USE_DOUBLE_ME)
419#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
420 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
421 } while (0)
422#else
423#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
424 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
425 } while (0)
426#endif
427#else /* DUK_USE_64BIT_OPS */
428#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
429 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
430 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
431 } while (0)
432#endif /* DUK_USE_64BIT_OPS */
433
434#if defined(DUK_USE_64BIT_OPS)
435/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
436#if defined(DUK_USE_DOUBLE_ME)
437#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
438 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
439 ((duk_uint64_t) (flags)) | \
440 (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
441 } while (0)
442#else
443#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
444 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
445 (((duk_uint64_t) (flags)) << 32) | \
446 ((duk_uint64_t) (duk_uint32_t) (fp)); \
447 } while (0)
448#endif
449#else /* DUK_USE_64BIT_OPS */
450#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
451 (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
452 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
453 } while (0)
454#endif /* DUK_USE_64BIT_OPS */
455
456#if defined(DUK_USE_FASTINT)
457/* Note: masking is done for 'i' to deal with negative numbers correctly */
458#if defined(DUK_USE_DOUBLE_ME)
459#define DUK__TVAL_SET_FASTINT(v,i) do { \
460 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
461 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
462 } while (0)
463#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
464 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
465 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
466 } while (0)
467#else
468#define DUK__TVAL_SET_FASTINT(v,i) do { \
469 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
470 } while (0)
471#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
472 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
473 } while (0)
474#endif
475
476#define DUK__TVAL_SET_FASTINT_I32(v,i) do { \
477 duk_int64_t duk__tmp = (duk_int64_t) (i); \
478 DUK_TVAL_SET_FASTINT((v), duk__tmp); \
479 } while (0)
480
481/* XXX: clumsy sign extend and masking of 16 topmost bits */
482#if defined(DUK_USE_DOUBLE_ME)
483#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)
484#else
485#define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
486#endif
487#define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1])
488#define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1])
489#endif /* DUK_USE_FASTINT */
490
491#define DUK_TVAL_SET_UNDEFINED(v) do { \
492 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
493 } while (0)
494#define DUK_TVAL_SET_UNUSED(v) do { \
495 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
496 } while (0)
497#define DUK_TVAL_SET_NULL(v) do { \
498 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
499 } while (0)
500
501#define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
502
503#define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v))
504
505/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
506#if defined(DUK_USE_FASTINT)
507#define DUK_TVAL_SET_DOUBLE(v,d) do { \
508 duk_double_t duk__dblval; \
509 duk__dblval = (d); \
510 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
511 DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
512 } while (0)
513#define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i))
514#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i))
515#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i))
516#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d))
517#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
518#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
519 duk_tval *duk__tv; \
520 duk_double_t duk__d; \
521 duk__tv = (v); \
522 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
523 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
524 DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
525 } \
526 } while (0)
527#else
528#define DUK_TVAL_SET_DOUBLE(v,d) do { \
529 duk_double_t duk__dblval; \
530 duk__dblval = (d); \
531 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
532 DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
533 } while (0)
534#define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */
535#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
536#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
537#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
538#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
539#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
540#endif
541
542#define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags))
543#define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING)
544#define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT)
545#define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER)
546#define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER)
547
548#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
549
550/* getters */
551#define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1])
552#if defined(DUK_USE_FASTINT)
553#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
554#define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v))
555#define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v))
556#define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v))
557#define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v))
558#else
559#define DUK_TVAL_GET_NUMBER(v) ((v)->d)
560#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
561#endif
562#define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \
563 (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
564 (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \
565 } while (0)
566#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1]))
567#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
568#define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1])
569#define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1])
570#define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1])
571#define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1])
572#define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1])
573
574/* decoding */
575#define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0])
576
577#define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED)
578#define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED)
579#define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL)
580#define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN)
581#define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
582#define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
583#define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC)
584#define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING)
585#define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT)
586#define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER)
587#define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER)
588#if defined(DUK_USE_FASTINT)
589/* 0xfff0 is -Infinity */
590#define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
591#define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT)
592#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL)
593#else
594#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
595#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
596#endif
597
598/* This is performance critical because it appears in every DECREF. */
599#define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING)
600
601#if defined(DUK_USE_FASTINT)
602DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
603#endif
604
605#else /* DUK_USE_PACKED_TVAL */
606/* ======================================================================== */
607
608/*
609 * Portable 12-byte representation
610 */
611
612/* Note: not initializing all bytes is normally not an issue: Duktape won't
613 * read or use the uninitialized bytes so valgrind won't issue warnings.
614 * In some special cases a harmless valgrind warning may be issued though.
615 * For example, the DumpHeap debugger command writes out a compiled function's
616 * 'data' area as is, including any uninitialized bytes, which causes a
617 * valgrind warning.
618 */
619
620typedef struct duk_tval_struct duk_tval;
621
622struct duk_tval_struct {
623 duk_small_uint_t t;
624 duk_small_uint_t v_extra;
625 union {
626 duk_double_t d;
627 duk_small_int_t i;
628#if defined(DUK_USE_FASTINT)
629 duk_int64_t fi; /* if present, forces 16-byte duk_tval */
630#endif
631 void *voidptr;
632 duk_hstring *hstring;
633 duk_hobject *hobject;
634 duk_hcompiledfunction *hcompiledfunction;
635 duk_hnativefunction *hnativefunction;
636 duk_hthread *hthread;
637 duk_hbuffer *hbuffer;
638 duk_heaphdr *heaphdr;
639 duk_c_function lightfunc;
640 } v;
641};
642
643#define DUK__TAG_NUMBER 0 /* not exposed */
644#if defined(DUK_USE_FASTINT)
645#define DUK_TAG_FASTINT 1
646#endif
647#define DUK_TAG_UNDEFINED 2
648#define DUK_TAG_NULL 3
649#define DUK_TAG_BOOLEAN 4
650#define DUK_TAG_POINTER 5
651#define DUK_TAG_LIGHTFUNC 6
652#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */
653#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
654#define DUK_TAG_OBJECT 9
655#define DUK_TAG_BUFFER 10
656
657/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code
658 * to support the 8-byte representation. Further, it is a non-heap-allocated
659 * type so it should come before DUK_TAG_STRING. Finally, it should not break
660 * the tag value ranges covered by case-clauses in a switch-case.
661 */
662
663/* setters */
664#define DUK_TVAL_SET_UNDEFINED(tv) do { \
665 (tv)->t = DUK_TAG_UNDEFINED; \
666 } while (0)
667
668#define DUK_TVAL_SET_UNUSED(tv) do { \
669 (tv)->t = DUK_TAG_UNUSED; \
670 } while (0)
671
672#define DUK_TVAL_SET_NULL(tv) do { \
673 (tv)->t = DUK_TAG_NULL; \
674 } while (0)
675
676#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
677 (tv)->t = DUK_TAG_BOOLEAN; \
678 (tv)->v.i = (val); \
679 } while (0)
680
681#if defined(DUK_USE_FASTINT)
682#define DUK_TVAL_SET_DOUBLE(tv,val) do { \
683 (tv)->t = DUK__TAG_NUMBER; \
684 (tv)->v.d = (val); \
685 } while (0)
686#define DUK_TVAL_SET_FASTINT(tv,val) do { \
687 (tv)->t = DUK_TAG_FASTINT; \
688 (tv)->v.fi = (val); \
689 } while (0)
690#define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \
691 (tv)->t = DUK_TAG_FASTINT; \
692 (tv)->v.fi = (duk_int64_t) (val); \
693 } while (0)
694#define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \
695 (tv)->t = DUK_TAG_FASTINT; \
696 (tv)->v.fi = (duk_int64_t) (val); \
697 } while (0)
698#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
699 duk_tval_set_number_chkfast((tv), (d))
700#define DUK_TVAL_SET_NUMBER(tv,val) \
701 DUK_TVAL_SET_DOUBLE((tv), (val))
702#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
703 duk_tval *duk__tv; \
704 duk_double_t duk__d; \
705 duk__tv = (v); \
706 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
707 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
708 DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
709 } \
710 } while (0)
711#else
712#define DUK_TVAL_SET_DOUBLE(tv,d) \
713 DUK_TVAL_SET_NUMBER((tv), (d))
714#define DUK_TVAL_SET_FASTINT(tv,val) \
715 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
716#define DUK_TVAL_SET_FASTINT_U32(tv,val) \
717 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
718#define DUK_TVAL_SET_FASTINT_I32(tv,val) \
719 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
720#define DUK_TVAL_SET_NUMBER(tv,val) do { \
721 (tv)->t = DUK__TAG_NUMBER; \
722 (tv)->v.d = (val); \
723 } while (0)
724#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
725 DUK_TVAL_SET_NUMBER((tv), (d))
726#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
727#endif /* DUK_USE_FASTINT */
728
729#define DUK_TVAL_SET_POINTER(tv,hptr) do { \
730 (tv)->t = DUK_TAG_POINTER; \
731 (tv)->v.voidptr = (hptr); \
732 } while (0)
733
734#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
735 (tv)->t = DUK_TAG_LIGHTFUNC; \
736 (tv)->v_extra = (flags); \
737 (tv)->v.lightfunc = (duk_c_function) (fp); \
738 } while (0)
739
740#define DUK_TVAL_SET_STRING(tv,hptr) do { \
741 (tv)->t = DUK_TAG_STRING; \
742 (tv)->v.hstring = (hptr); \
743 } while (0)
744
745#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
746 (tv)->t = DUK_TAG_OBJECT; \
747 (tv)->v.hobject = (hptr); \
748 } while (0)
749
750#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
751 (tv)->t = DUK_TAG_BUFFER; \
752 (tv)->v.hbuffer = (hptr); \
753 } while (0)
754
755#define DUK_TVAL_SET_NAN(tv) do { \
756 /* in non-packed representation we don't care about which NaN is used */ \
757 (tv)->t = DUK__TAG_NUMBER; \
758 (tv)->v.d = DUK_DOUBLE_NAN; \
759 } while (0)
760
761#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
762
763/* getters */
764#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
765#if defined(DUK_USE_FASTINT)
766#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
767#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
768#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi))
769#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi))
770#if 0
771#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
772 (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \
773 DUK_TVAL_GET_DOUBLE((tv)))
774#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv))
775#else
776/* This seems reasonable overall. */
777#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
778 duk_tval_get_number_unpacked_fastint((tv)) : \
779 DUK_TVAL_GET_DOUBLE((tv)))
780#endif
781#else
782#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d)
783#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
784#endif /* DUK_USE_FASTINT */
785#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr)
786#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
787 (out_flags) = (duk_uint32_t) (tv)->v_extra; \
788 (out_fp) = (tv)->v.lightfunc; \
789 } while (0)
790#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
791#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
792#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
793#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
794#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
795#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr)
796
797/* decoding */
798#define DUK_TVAL_GET_TAG(tv) ((tv)->t)
799#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED)
800#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED)
801#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL)
802#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN)
803#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
804#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
805#if defined(DUK_USE_FASTINT)
806#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER)
807#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
808#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \
809 (tv)->t == DUK_TAG_FASTINT)
810#else
811#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER)
812#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
813#endif /* DUK_USE_FASTINT */
814#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
815#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
816#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING)
817#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT)
818#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER)
819
820/* This is performance critical because it's needed for every DECREF.
821 * Take advantage of the fact that the first heap allocated tag is 8,
822 * so that bit 3 is set for all heap allocated tags (and never set for
823 * non-heap-allocated tags).
824 */
825#if 0
826#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING)
827#endif
828#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08)
829
830#if defined(DUK_USE_FASTINT)
831#if 0
832DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
833#endif
834DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
835#endif
836
837#endif /* DUK_USE_PACKED_TVAL */
838
839/*
840 * Convenience (independent of representation)
841 */
842
843#define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1)
844#define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0)
845
846/* Lightfunc flags packing and unpacking. */
847/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */
848#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
849 ((((duk_int32_t) (lf_flags)) << 16) >> 24)
850#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
851 (((lf_flags) >> 4) & 0x0f)
852#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
853 ((lf_flags) & 0x0f)
854#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
855 (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
856
857#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
858#define DUK_LFUNC_NARGS_MIN 0x00
859#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */
860#define DUK_LFUNC_LENGTH_MIN 0x00
861#define DUK_LFUNC_LENGTH_MAX 0x0f
862#define DUK_LFUNC_MAGIC_MIN (-0x80)
863#define DUK_LFUNC_MAGIC_MAX 0x7f
864
865/* fastint constants etc */
866#if defined(DUK_USE_FASTINT)
867#define DUK_FASTINT_MIN (-0x800000000000LL)
868#define DUK_FASTINT_MAX 0x7fffffffffffLL
869#define DUK_FASTINT_BITS 48
870
871DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x);
872#endif
873
874#endif /* DUK_TVAL_H_INCLUDED */
875#line 1 "duk_builtins.h"
876/*
877 * Automatically generated by genbuiltins.py, do not edit!
878 */
879
880#ifndef DUK_BUILTINS_H_INCLUDED
881#define DUK_BUILTINS_H_INCLUDED
882
883#if defined(DUK_USE_ROM_STRINGS)
884#error ROM support not enabled, rerun make_dist.py with --rom-support
885#else /* DUK_USE_ROM_STRINGS */
886#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
887#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
888#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED)
889#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
890#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
891#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
892#define DUK_STRIDX_UC_ARGUMENTS 2 /* 'Arguments' */
893#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
894#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
895#define DUK_STRIDX_UC_OBJECT 3 /* 'Object' */
896#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
897#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
898#define DUK_STRIDX_UC_FUNCTION 4 /* 'Function' */
899#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
900#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
901#define DUK_STRIDX_ARRAY 5 /* 'Array' */
902#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
903#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
904#define DUK_STRIDX_UC_STRING 6 /* 'String' */
905#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
906#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
907#define DUK_STRIDX_UC_BOOLEAN 7 /* 'Boolean' */
908#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
909#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
910#define DUK_STRIDX_UC_NUMBER 8 /* 'Number' */
911#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
912#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
913#define DUK_STRIDX_DATE 9 /* 'Date' */
914#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
915#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
916#define DUK_STRIDX_REG_EXP 10 /* 'RegExp' */
917#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
918#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
919#define DUK_STRIDX_UC_ERROR 11 /* 'Error' */
920#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
921#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
922#define DUK_STRIDX_MATH 12 /* 'Math' */
923#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
924#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
925#define DUK_STRIDX_JSON 13 /* 'JSON' */
926#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
927#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
928#define DUK_STRIDX_EMPTY_STRING 14 /* '' */
929#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
930#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
931#define DUK_STRIDX_ARRAY_BUFFER 15 /* 'ArrayBuffer' */
932#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
933#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
934#define DUK_STRIDX_DATA_VIEW 16 /* 'DataView' */
935#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
936#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
937#define DUK_STRIDX_INT8_ARRAY 17 /* 'Int8Array' */
938#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
939#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
940#define DUK_STRIDX_UINT8_ARRAY 18 /* 'Uint8Array' */
941#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
942#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
943#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 19 /* 'Uint8ClampedArray' */
944#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
945#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
946#define DUK_STRIDX_INT16_ARRAY 20 /* 'Int16Array' */
947#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
948#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
949#define DUK_STRIDX_UINT16_ARRAY 21 /* 'Uint16Array' */
950#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
951#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
952#define DUK_STRIDX_INT32_ARRAY 22 /* 'Int32Array' */
953#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
954#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
955#define DUK_STRIDX_UINT32_ARRAY 23 /* 'Uint32Array' */
956#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
957#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
958#define DUK_STRIDX_FLOAT32_ARRAY 24 /* 'Float32Array' */
959#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
960#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
961#define DUK_STRIDX_FLOAT64_ARRAY 25 /* 'Float64Array' */
962#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
963#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
964#define DUK_STRIDX_GLOBAL 26 /* 'global' */
965#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
966#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
967#define DUK_STRIDX_OBJ_ENV 27 /* 'ObjEnv' */
968#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
969#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
970#define DUK_STRIDX_DEC_ENV 28 /* 'DecEnv' */
971#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
972#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
973#define DUK_STRIDX_UC_BUFFER 29 /* 'Buffer' */
974#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
975#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
976#define DUK_STRIDX_UC_POINTER 30 /* 'Pointer' */
977#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
978#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
979#define DUK_STRIDX_UC_THREAD 31 /* 'Thread' */
980#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
981#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
982#define DUK_STRIDX_EVAL 32 /* 'eval' */
983#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
984#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
985#define DUK_STRIDX_DEFINE_PROPERTY 33 /* 'defineProperty' */
986#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
987#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
988#define DUK_STRIDX_VALUE 34 /* 'value' */
989#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
990#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
991#define DUK_STRIDX_WRITABLE 35 /* 'writable' */
992#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
993#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
994#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */
995#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
996#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
997#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */
998#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
999#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
1000#define DUK_STRIDX_JOIN 38 /* 'join' */
1001#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
1002#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
1003#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */
1004#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
1005#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
1006#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */
1007#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
1008#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
1009#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */
1010#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
1011#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
1012#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */
1013#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
1014#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
1015#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */
1016#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
1017#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
1018#define DUK_STRIDX_SOURCE 44 /* 'source' */
1019#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
1020#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
1021#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */
1022#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
1023#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
1024#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */
1025#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
1026#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
1027#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
1028#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
1029#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
1030#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP 48 /* '(?:)' */
1031#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
1032#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
1033#define DUK_STRIDX_INDEX 49 /* 'index' */
1034#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
1035#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
1036#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */
1037#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
1038#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
1039#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */
1040#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
1041#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
1042#define DUK_STRIDX_MESSAGE 52 /* 'message' */
1043#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
1044#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
1045#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */
1046#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
1047#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
1048#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */
1049#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
1050#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
1051#define DUK_STRIDX_LC_STRING 55 /* 'string' */
1052#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
1053#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
1054#define DUK_STRIDX_LC_OBJECT 56 /* 'object' */
1055#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
1056#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
1057#define DUK_STRIDX_LC_UNDEFINED 57 /* 'undefined' */
1058#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
1059#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
1060#define DUK_STRIDX_NAN 58 /* 'NaN' */
1061#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
1062#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
1063#define DUK_STRIDX_INFINITY 59 /* 'Infinity' */
1064#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
1065#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
1066#define DUK_STRIDX_MINUS_INFINITY 60 /* '-Infinity' */
1067#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
1068#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
1069#define DUK_STRIDX_MINUS_ZERO 61 /* '-0' */
1070#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
1071#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
1072#define DUK_STRIDX_COMMA 62 /* ',' */
1073#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
1074#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
1075#define DUK_STRIDX_SPACE 63 /* ' ' */
1076#define DUK_HEAP_STRING_SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
1077#define DUK_HTHREAD_STRING_SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
1078#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
1079#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
1080#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
1081#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */
1082#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
1083#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
1084#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */
1085#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
1086#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
1087#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */
1088#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
1089#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
1090#define DUK_STRIDX_CALLEE 68 /* 'callee' */
1091#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
1092#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
1093#define DUK_STRIDX_CALLER 69 /* 'caller' */
1094#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
1095#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
1096#define DUK_STRIDX_HAS 70 /* 'has' */
1097#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
1098#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
1099#define DUK_STRIDX_GET 71 /* 'get' */
1100#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
1101#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
1102#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
1103#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
1104#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
1105#define DUK_STRIDX_ENUMERATE 73 /* 'enumerate' */
1106#define DUK_HEAP_STRING_ENUMERATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERATE)
1107#define DUK_HTHREAD_STRING_ENUMERATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERATE)
1108#define DUK_STRIDX_OWN_KEYS 74 /* 'ownKeys' */
1109#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
1110#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
1111#define DUK_STRIDX_SET_PROTOTYPE_OF 75 /* 'setPrototypeOf' */
1112#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
1113#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
1114#define DUK_STRIDX___PROTO__ 76 /* '__proto__' */
1115#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
1116#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
1117#define DUK_STRIDX_REQUIRE 77 /* 'require' */
1118#define DUK_HEAP_STRING_REQUIRE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REQUIRE)
1119#define DUK_HTHREAD_STRING_REQUIRE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REQUIRE)
1120#define DUK_STRIDX_ID 78 /* 'id' */
1121#define DUK_HEAP_STRING_ID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ID)
1122#define DUK_HTHREAD_STRING_ID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ID)
1123#define DUK_STRIDX_EXPORTS 79 /* 'exports' */
1124#define DUK_HEAP_STRING_EXPORTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORTS)
1125#define DUK_HTHREAD_STRING_EXPORTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORTS)
1126#define DUK_STRIDX_FILENAME 80 /* 'filename' */
1127#define DUK_HEAP_STRING_FILENAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILENAME)
1128#define DUK_HTHREAD_STRING_FILENAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILENAME)
1129#define DUK_STRIDX_TO_STRING 81 /* 'toString' */
1130#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
1131#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
1132#define DUK_STRIDX_TO_JSON 82 /* 'toJSON' */
1133#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
1134#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
1135#define DUK_STRIDX_TYPE 83 /* 'type' */
1136#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
1137#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
1138#define DUK_STRIDX_DATA 84 /* 'data' */
1139#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
1140#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
1141#define DUK_STRIDX_LENGTH 85 /* 'length' */
1142#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
1143#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
1144#define DUK_STRIDX_BYTE_LENGTH 86 /* 'byteLength' */
1145#define DUK_HEAP_STRING_BYTE_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_LENGTH)
1146#define DUK_HTHREAD_STRING_BYTE_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_LENGTH)
1147#define DUK_STRIDX_BYTE_OFFSET 87 /* 'byteOffset' */
1148#define DUK_HEAP_STRING_BYTE_OFFSET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_OFFSET)
1149#define DUK_HTHREAD_STRING_BYTE_OFFSET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_OFFSET)
1150#define DUK_STRIDX_BYTES_PER_ELEMENT 88 /* 'BYTES_PER_ELEMENT' */
1151#define DUK_HEAP_STRING_BYTES_PER_ELEMENT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTES_PER_ELEMENT)
1152#define DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTES_PER_ELEMENT)
1153#define DUK_STRIDX_SET 89 /* 'set' */
1154#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
1155#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
1156#define DUK_STRIDX_STACK 90 /* 'stack' */
1157#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
1158#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
1159#define DUK_STRIDX_PC 91 /* 'pc' */
1160#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
1161#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
1162#define DUK_STRIDX_LINE_NUMBER 92 /* 'lineNumber' */
1163#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
1164#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
1165#define DUK_STRIDX_INT_TRACEDATA 93 /* '\xffTracedata' */
1166#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
1167#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
1168#define DUK_STRIDX_NAME 94 /* 'name' */
1169#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
1170#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
1171#define DUK_STRIDX_FILE_NAME 95 /* 'fileName' */
1172#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
1173#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
1174#define DUK_STRIDX_LC_BUFFER 96 /* 'buffer' */
1175#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
1176#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
1177#define DUK_STRIDX_LC_POINTER 97 /* 'pointer' */
1178#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
1179#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
1180#define DUK_STRIDX_INT_VALUE 98 /* '\xffValue' */
1181#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
1182#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
1183#define DUK_STRIDX_INT_NEXT 99 /* '\xffNext' */
1184#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
1185#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
1186#define DUK_STRIDX_INT_BYTECODE 100 /* '\xffBytecode' */
1187#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
1188#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
1189#define DUK_STRIDX_INT_FORMALS 101 /* '\xffFormals' */
1190#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
1191#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
1192#define DUK_STRIDX_INT_VARMAP 102 /* '\xffVarmap' */
1193#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
1194#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
1195#define DUK_STRIDX_INT_LEXENV 103 /* '\xffLexenv' */
1196#define DUK_HEAP_STRING_INT_LEXENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
1197#define DUK_HTHREAD_STRING_INT_LEXENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
1198#define DUK_STRIDX_INT_VARENV 104 /* '\xffVarenv' */
1199#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
1200#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
1201#define DUK_STRIDX_INT_SOURCE 105 /* '\xffSource' */
1202#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
1203#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
1204#define DUK_STRIDX_INT_PC2LINE 106 /* '\xffPc2line' */
1205#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
1206#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
1207#define DUK_STRIDX_INT_ARGS 107 /* '\xffArgs' */
1208#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
1209#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
1210#define DUK_STRIDX_INT_MAP 108 /* '\xffMap' */
1211#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
1212#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
1213#define DUK_STRIDX_INT_FINALIZER 109 /* '\xffFinalizer' */
1214#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
1215#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
1216#define DUK_STRIDX_INT_HANDLER 110 /* '\xffHandler' */
1217#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER)
1218#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER)
1219#define DUK_STRIDX_INT_CALLEE 111 /* '\xffCallee' */
1220#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
1221#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
1222#define DUK_STRIDX_INT_THREAD 112 /* '\xffThread' */
1223#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
1224#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
1225#define DUK_STRIDX_INT_REGBASE 113 /* '\xffRegbase' */
1226#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
1227#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
1228#define DUK_STRIDX_INT_TARGET 114 /* '\xffTarget' */
1229#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
1230#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
1231#define DUK_STRIDX_INT_THIS 115 /* '\xffThis' */
1232#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
1233#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
1234#define DUK_STRIDX_COMPILE 116 /* 'compile' */
1235#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
1236#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
1237#define DUK_STRIDX_INPUT 117 /* 'input' */
1238#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
1239#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
1240#define DUK_STRIDX_ERR_CREATE 118 /* 'errCreate' */
1241#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
1242#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
1243#define DUK_STRIDX_ERR_THROW 119 /* 'errThrow' */
1244#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
1245#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
1246#define DUK_STRIDX_MOD_SEARCH 120 /* 'modSearch' */
1247#define DUK_HEAP_STRING_MOD_SEARCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_SEARCH)
1248#define DUK_HTHREAD_STRING_MOD_SEARCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_SEARCH)
1249#define DUK_STRIDX_MOD_LOADED 121 /* 'modLoaded' */
1250#define DUK_HEAP_STRING_MOD_LOADED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_LOADED)
1251#define DUK_HTHREAD_STRING_MOD_LOADED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_LOADED)
1252#define DUK_STRIDX_ENV 122 /* 'env' */
1253#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
1254#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
1255#define DUK_STRIDX_HEX 123 /* 'hex' */
1256#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
1257#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
1258#define DUK_STRIDX_BASE64 124 /* 'base64' */
1259#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
1260#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
1261#define DUK_STRIDX_JX 125 /* 'jx' */
1262#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
1263#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
1264#define DUK_STRIDX_JC 126 /* 'jc' */
1265#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
1266#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
1267#define DUK_STRIDX_RESUME 127 /* 'resume' */
1268#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
1269#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
1270#define DUK_STRIDX_FMT 128 /* 'fmt' */
1271#define DUK_HEAP_STRING_FMT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
1272#define DUK_HTHREAD_STRING_FMT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
1273#define DUK_STRIDX_RAW 129 /* 'raw' */
1274#define DUK_HEAP_STRING_RAW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
1275#define DUK_HTHREAD_STRING_RAW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
1276#define DUK_STRIDX_LC_TRACE 130 /* 'trace' */
1277#define DUK_HEAP_STRING_LC_TRACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
1278#define DUK_HTHREAD_STRING_LC_TRACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
1279#define DUK_STRIDX_LC_DEBUG 131 /* 'debug' */
1280#define DUK_HEAP_STRING_LC_DEBUG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
1281#define DUK_HTHREAD_STRING_LC_DEBUG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
1282#define DUK_STRIDX_LC_INFO 132 /* 'info' */
1283#define DUK_HEAP_STRING_LC_INFO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
1284#define DUK_HTHREAD_STRING_LC_INFO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
1285#define DUK_STRIDX_LC_WARN 133 /* 'warn' */
1286#define DUK_HEAP_STRING_LC_WARN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
1287#define DUK_HTHREAD_STRING_LC_WARN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
1288#define DUK_STRIDX_LC_ERROR 134 /* 'error' */
1289#define DUK_HEAP_STRING_LC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
1290#define DUK_HTHREAD_STRING_LC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
1291#define DUK_STRIDX_LC_FATAL 135 /* 'fatal' */
1292#define DUK_HEAP_STRING_LC_FATAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
1293#define DUK_HTHREAD_STRING_LC_FATAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
1294#define DUK_STRIDX_LC_N 136 /* 'n' */
1295#define DUK_HEAP_STRING_LC_N(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
1296#define DUK_HTHREAD_STRING_LC_N(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
1297#define DUK_STRIDX_LC_L 137 /* 'l' */
1298#define DUK_HEAP_STRING_LC_L(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
1299#define DUK_HTHREAD_STRING_LC_L(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
1300#define DUK_STRIDX_CLOG 138 /* 'clog' */
1301#define DUK_HEAP_STRING_CLOG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
1302#define DUK_HTHREAD_STRING_CLOG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
1303#define DUK_STRIDX_TO_LOG_STRING 139 /* 'toLogString' */
1304#define DUK_HEAP_STRING_TO_LOG_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
1305#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
1306#define DUK_STRIDX_JSON_EXT_UNDEFINED 140 /* '{"_undef":true}' */
1307#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
1308#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
1309#define DUK_STRIDX_JSON_EXT_NAN 141 /* '{"_nan":true}' */
1310#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
1311#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
1312#define DUK_STRIDX_JSON_EXT_POSINF 142 /* '{"_inf":true}' */
1313#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
1314#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
1315#define DUK_STRIDX_JSON_EXT_NEGINF 143 /* '{"_ninf":true}' */
1316#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
1317#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
1318#define DUK_STRIDX_JSON_EXT_FUNCTION1 144 /* '{"_func":true}' */
1319#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
1320#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
1321#define DUK_STRIDX_JSON_EXT_FUNCTION2 145 /* '{_func:true}' */
1322#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
1323#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
1324#define DUK_STRIDX_BREAK 146 /* 'break' */
1325#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
1326#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
1327#define DUK_STRIDX_CASE 147 /* 'case' */
1328#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
1329#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
1330#define DUK_STRIDX_CATCH 148 /* 'catch' */
1331#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
1332#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
1333#define DUK_STRIDX_CONTINUE 149 /* 'continue' */
1334#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
1335#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
1336#define DUK_STRIDX_DEBUGGER 150 /* 'debugger' */
1337#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
1338#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
1339#define DUK_STRIDX_DEFAULT 151 /* 'default' */
1340#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
1341#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
1342#define DUK_STRIDX_DELETE 152 /* 'delete' */
1343#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
1344#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
1345#define DUK_STRIDX_DO 153 /* 'do' */
1346#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
1347#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
1348#define DUK_STRIDX_ELSE 154 /* 'else' */
1349#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
1350#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
1351#define DUK_STRIDX_FINALLY 155 /* 'finally' */
1352#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
1353#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
1354#define DUK_STRIDX_FOR 156 /* 'for' */
1355#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
1356#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
1357#define DUK_STRIDX_LC_FUNCTION 157 /* 'function' */
1358#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
1359#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
1360#define DUK_STRIDX_IF 158 /* 'if' */
1361#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
1362#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
1363#define DUK_STRIDX_IN 159 /* 'in' */
1364#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
1365#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
1366#define DUK_STRIDX_INSTANCEOF 160 /* 'instanceof' */
1367#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
1368#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
1369#define DUK_STRIDX_NEW 161 /* 'new' */
1370#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
1371#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
1372#define DUK_STRIDX_RETURN 162 /* 'return' */
1373#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
1374#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
1375#define DUK_STRIDX_SWITCH 163 /* 'switch' */
1376#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
1377#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
1378#define DUK_STRIDX_THIS 164 /* 'this' */
1379#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
1380#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
1381#define DUK_STRIDX_THROW 165 /* 'throw' */
1382#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
1383#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
1384#define DUK_STRIDX_TRY 166 /* 'try' */
1385#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
1386#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
1387#define DUK_STRIDX_TYPEOF 167 /* 'typeof' */
1388#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
1389#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
1390#define DUK_STRIDX_VAR 168 /* 'var' */
1391#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
1392#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
1393#define DUK_STRIDX_CONST 169 /* 'const' */
1394#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
1395#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
1396#define DUK_STRIDX_VOID 170 /* 'void' */
1397#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
1398#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
1399#define DUK_STRIDX_WHILE 171 /* 'while' */
1400#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
1401#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
1402#define DUK_STRIDX_WITH 172 /* 'with' */
1403#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
1404#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
1405#define DUK_STRIDX_CLASS 173 /* 'class' */
1406#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
1407#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
1408#define DUK_STRIDX_ENUM 174 /* 'enum' */
1409#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
1410#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
1411#define DUK_STRIDX_EXPORT 175 /* 'export' */
1412#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
1413#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
1414#define DUK_STRIDX_EXTENDS 176 /* 'extends' */
1415#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
1416#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
1417#define DUK_STRIDX_IMPORT 177 /* 'import' */
1418#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
1419#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
1420#define DUK_STRIDX_SUPER 178 /* 'super' */
1421#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
1422#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
1423#define DUK_STRIDX_LC_NULL 179 /* 'null' */
1424#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
1425#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
1426#define DUK_STRIDX_TRUE 180 /* 'true' */
1427#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
1428#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
1429#define DUK_STRIDX_FALSE 181 /* 'false' */
1430#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
1431#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
1432#define DUK_STRIDX_IMPLEMENTS 182 /* 'implements' */
1433#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
1434#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
1435#define DUK_STRIDX_INTERFACE 183 /* 'interface' */
1436#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
1437#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
1438#define DUK_STRIDX_LET 184 /* 'let' */
1439#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
1440#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
1441#define DUK_STRIDX_PACKAGE 185 /* 'package' */
1442#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
1443#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
1444#define DUK_STRIDX_PRIVATE 186 /* 'private' */
1445#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
1446#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
1447#define DUK_STRIDX_PROTECTED 187 /* 'protected' */
1448#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
1449#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
1450#define DUK_STRIDX_PUBLIC 188 /* 'public' */
1451#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
1452#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
1453#define DUK_STRIDX_STATIC 189 /* 'static' */
1454#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
1455#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
1456#define DUK_STRIDX_YIELD 190 /* 'yield' */
1457#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
1458#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
1459
1460#define DUK_HEAP_NUM_STRINGS 191
1461#define DUK_STRIDX_START_RESERVED 146
1462#define DUK_STRIDX_START_STRICT_RESERVED 182
1463#define DUK_STRIDX_END_RESERVED 191 /* exclusive endpoint */
1464
1465/* To convert a heap stridx to a token number, subtract
1466 * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
1467 */
1468#if !defined(DUK_SINGLE_FILE)
1469DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[1049];
1470#endif /* !DUK_SINGLE_FILE */
1471#define DUK_STRDATA_MAX_STRLEN 17
1472#define DUK_STRDATA_DATA_LENGTH 1049
1473#endif /* DUK_USE_ROM_STRINGS */
1474
1475#if defined(DUK_USE_ROM_OBJECTS)
1476#error ROM support not enabled, rerun make_dist.py with --rom-support
1477#else
1478DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
1479DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
1480DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
1481DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx);
1482DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx);
1483DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
1484DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx);
1485DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
1486DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
1487DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
1488DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
1489DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
1490DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
1491DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx);
1492DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
1493DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_constructor(duk_context *ctx);
1494DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
1495DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
1496DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
1497DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
1498DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
1499DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
1500DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
1501DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
1502DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
1503DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
1504DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
1505DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
1506DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
1507DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
1508DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
1509DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx);
1510DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_require(duk_context *ctx);
1511DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
1512DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
1513DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
1514DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
1515DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
1516DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
1517DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
1518DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
1519DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
1520DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
1521DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
1522DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
1523DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
1524DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
1525DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
1526DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
1527DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
1528DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
1529DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
1530DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
1531DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
1532DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
1533DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
1534DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
1535DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
1536DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
1537DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
1538DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
1539DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
1540DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
1541DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
1542DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
1543DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
1544DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
1545DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
1546DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
1547DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
1548DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
1549DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
1550DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
1551DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
1552DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
1553DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
1554DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
1555DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
1556DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
1557DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
1558DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
1559DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
1560DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
1561DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
1562DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
1563DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
1564DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
1565DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
1566DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
1567DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
1568DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
1569DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
1570DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
1571DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
1572DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
1573DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
1574DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
1575DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
1576DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
1577DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
1578DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
1579DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
1580DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
1581DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
1582DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx);
1583DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
1584DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
1585DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
1586DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
1587DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
1588DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
1589DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
1590DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
1591DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
1592DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
1593DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
1594DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
1595DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
1596DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
1597DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
1598DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
1599DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
1600DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
1601DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
1602DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
1603DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
1604DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
1605DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
1606DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
1607DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx);
1608DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
1609DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx);
1610DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx);
1611DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx);
1612DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
1613DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
1614DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
1615DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
1616DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
1617DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
1618DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
1619DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
1620DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx);
1621DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx);
1622DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx);
1623DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
1624DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
1625DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
1626DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
1627#if !defined(DUK_SINGLE_FILE)
1628DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
1629#endif /* !DUK_SINGLE_FILE */
1630#if defined(DUK_USE_BUILTIN_INITJS)
1631#if !defined(DUK_SINGLE_FILE)
1632DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204];
1633#endif /* !DUK_SINGLE_FILE */
1634#define DUK_BUILTIN_INITJS_DATA_LENGTH 204
1635#endif /* DUK_USE_BUILTIN_INITJS */
1636#define DUK_BIDX_GLOBAL 0
1637#define DUK_BIDX_GLOBAL_ENV 1
1638#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
1639#define DUK_BIDX_OBJECT_PROTOTYPE 3
1640#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
1641#define DUK_BIDX_FUNCTION_PROTOTYPE 5
1642#define DUK_BIDX_ARRAY_CONSTRUCTOR 6
1643#define DUK_BIDX_ARRAY_PROTOTYPE 7
1644#define DUK_BIDX_STRING_CONSTRUCTOR 8
1645#define DUK_BIDX_STRING_PROTOTYPE 9
1646#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10
1647#define DUK_BIDX_BOOLEAN_PROTOTYPE 11
1648#define DUK_BIDX_NUMBER_CONSTRUCTOR 12
1649#define DUK_BIDX_NUMBER_PROTOTYPE 13
1650#define DUK_BIDX_DATE_CONSTRUCTOR 14
1651#define DUK_BIDX_DATE_PROTOTYPE 15
1652#define DUK_BIDX_REGEXP_CONSTRUCTOR 16
1653#define DUK_BIDX_REGEXP_PROTOTYPE 17
1654#define DUK_BIDX_ERROR_CONSTRUCTOR 18
1655#define DUK_BIDX_ERROR_PROTOTYPE 19
1656#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20
1657#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21
1658#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22
1659#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23
1660#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24
1661#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25
1662#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26
1663#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27
1664#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28
1665#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29
1666#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30
1667#define DUK_BIDX_URI_ERROR_PROTOTYPE 31
1668#define DUK_BIDX_MATH 32
1669#define DUK_BIDX_JSON 33
1670#define DUK_BIDX_TYPE_ERROR_THROWER 34
1671#define DUK_BIDX_PROXY_CONSTRUCTOR 35
1672#define DUK_BIDX_DUKTAPE 36
1673#define DUK_BIDX_THREAD_CONSTRUCTOR 37
1674#define DUK_BIDX_THREAD_PROTOTYPE 38
1675#define DUK_BIDX_BUFFER_CONSTRUCTOR 39
1676#define DUK_BIDX_BUFFER_PROTOTYPE 40
1677#define DUK_BIDX_POINTER_CONSTRUCTOR 41
1678#define DUK_BIDX_POINTER_PROTOTYPE 42
1679#define DUK_BIDX_LOGGER_CONSTRUCTOR 43
1680#define DUK_BIDX_LOGGER_PROTOTYPE 44
1681#define DUK_BIDX_DOUBLE_ERROR 45
1682#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 46
1683#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 47
1684#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 48
1685#define DUK_BIDX_DATAVIEW_PROTOTYPE 49
1686#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 50
1687#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 51
1688#define DUK_BIDX_INT8ARRAY_PROTOTYPE 52
1689#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 53
1690#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 54
1691#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 55
1692#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 56
1693#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 57
1694#define DUK_BIDX_INT16ARRAY_PROTOTYPE 58
1695#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 59
1696#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 60
1697#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 61
1698#define DUK_BIDX_INT32ARRAY_PROTOTYPE 62
1699#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 63
1700#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 64
1701#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 65
1702#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 66
1703#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 67
1704#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 68
1705#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 69
1706#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 70
1707#define DUK_NUM_BUILTINS 71
1708#define DUK_NUM_BIDX_BUILTINS 71
1709#define DUK_NUM_ALL_BUILTINS 71
1710#if defined(DUK_USE_DOUBLE_LE)
1711#if !defined(DUK_SINGLE_FILE)
1712DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
1713#endif /* !DUK_SINGLE_FILE */
1714#define DUK_BUILTINS_DATA_LENGTH 3833
1715#elif defined(DUK_USE_DOUBLE_BE)
1716#if !defined(DUK_SINGLE_FILE)
1717DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
1718#endif /* !DUK_SINGLE_FILE */
1719#define DUK_BUILTINS_DATA_LENGTH 3833
1720#elif defined(DUK_USE_DOUBLE_ME)
1721#if !defined(DUK_SINGLE_FILE)
1722DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
1723#endif /* !DUK_SINGLE_FILE */
1724#define DUK_BUILTINS_DATA_LENGTH 3833
1725#else
1726#error invalid endianness defines
1727#endif
1728#endif /* DUK_USE_ROM_OBJECTS */
1729#endif /* DUK_BUILTINS_H_INCLUDED */
1730#line 52 "duk_internal.h"
1731
1732#line 1 "duk_util.h"
1733/*
1734 * Utilities
1735 */
1736
1737#ifndef DUK_UTIL_H_INCLUDED
1738#define DUK_UTIL_H_INCLUDED
1739
1740#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */
1741
1742#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f])
1743
1744/*
1745 * Endian conversion
1746 */
1747
1748#if defined(DUK_USE_INTEGER_LE)
1749#define DUK_HTON32(x) DUK_BSWAP32((x))
1750#define DUK_NTOH32(x) DUK_BSWAP32((x))
1751#define DUK_HTON16(x) DUK_BSWAP16((x))
1752#define DUK_NTOH16(x) DUK_BSWAP16((x))
1753#elif defined(DUK_USE_INTEGER_BE)
1754#define DUK_HTON32(x) (x)
1755#define DUK_NTOH32(x) (x)
1756#define DUK_HTON16(x) (x)
1757#define DUK_NTOH16(x) (x)
1758#else
1759#error internal error, endianness defines broken
1760#endif
1761
1762/*
1763 * Bitstream decoder
1764 */
1765
1766struct duk_bitdecoder_ctx {
1767 const duk_uint8_t *data;
1768 duk_size_t offset;
1769 duk_size_t length;
1770 duk_uint32_t currval;
1771 duk_small_int_t currbits;
1772};
1773
1774/*
1775 * Bitstream encoder
1776 */
1777
1778struct duk_bitencoder_ctx {
1779 duk_uint8_t *data;
1780 duk_size_t offset;
1781 duk_size_t length;
1782 duk_uint32_t currval;
1783 duk_small_int_t currbits;
1784 duk_small_int_t truncated;
1785};
1786
1787/*
1788 * Raw write/read macros for big endian, unaligned basic values.
1789 * Caller ensures there's enough space. The macros update the pointer
1790 * argument automatically on resizes. The idiom seems a bit odd, but
1791 * leads to compact code.
1792 */
1793
1794#define DUK_RAW_WRITE_U8(ptr,val) do { \
1795 *(ptr)++ = (duk_uint8_t) (val); \
1796 } while (0)
1797#define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val))
1798#define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val))
1799#define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val))
1800#define DUK_RAW_WRITE_XUTF8(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_xutf8((duk_ucodepoint_t) (val), duk__ptr); \
1806 duk__ptr += duk__len; \
1807 (ptr) = duk__ptr; \
1808 } while (0)
1809#define DUK_RAW_WRITE_CESU8(ptr,val) do { \
1810 /* 'ptr' is evaluated both as LHS and RHS. */ \
1811 duk_uint8_t *duk__ptr; \
1812 duk_small_int_t duk__len; \
1813 duk__ptr = (duk_uint8_t *) (ptr); \
1814 duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \
1815 duk__ptr += duk__len; \
1816 (ptr) = duk__ptr; \
1817 } while (0)
1818
1819#define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++))
1820#define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr));
1821#define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr));
1822#define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr));
1823
1824/*
1825 * Buffer writer (dynamic buffer only)
1826 *
1827 * Helper for writing to a dynamic buffer with a concept of a "spare" area
1828 * to reduce resizes. You can ensure there is enough space beforehand and
1829 * then write for a while without further checks, relying on a stable data
1830 * pointer. Spare handling is automatic so call sites only indicate how
1831 * much data they need right now.
1832 *
1833 * There are several ways to write using bufwriter. The best approach
1834 * depends mainly on how much performance matters over code footprint.
1835 * The key issues are (1) ensuring there is space and (2) keeping the
1836 * pointers consistent. Fast code should ensure space for multiple writes
1837 * with one ensure call. Fastest inner loop code can temporarily borrow
1838 * the 'p' pointer but must write it back eventually.
1839 *
1840 * Be careful to ensure all macro arguments (other than static pointers like
1841 * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if
1842 * necessary (if that's not possible, there should be a note near the macro).
1843 * Buffer write arguments often contain arithmetic etc so this is
1844 * particularly important here.
1845 */
1846
1847/* XXX: Migrate bufwriter and other read/write helpers to its own header? */
1848
1849struct duk_bufwriter_ctx {
1850 duk_uint8_t *p;
1851 duk_uint8_t *p_base;
1852 duk_uint8_t *p_limit;
1853 duk_hbuffer_dynamic *buf;
1854};
1855
1856#define DUK_BW_SPARE_ADD 64
1857#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */
1858
1859/* Initialization and finalization (compaction), converting to other types. */
1860
1861#define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \
1862 duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \
1863 } while (0)
1864#define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \
1865 duk_bw_init((thr), (bw_ctx), (buf)); \
1866 } while (0)
1867#define DUK_BW_COMPACT(thr,bw_ctx) do { \
1868 /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \
1869 duk_bw_compact((thr), (bw_ctx)); \
1870 } while (0)
1871#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
1872 duk_push_lstring((duk_context *) (thr), \
1873 (const char *) (bw_ctx)->p_base, \
1874 (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
1875 } while (0)
1876/* Pointers may be NULL for a while when 'buf' size is zero and before any
1877 * ENSURE calls have been made. Once an ENSURE has been made, the pointers
1878 * are required to be non-NULL so that it's always valid to use memcpy() and
1879 * memmove(), even for zero size.
1880 */
1881#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \
1882 DUK_ASSERT_EXPR((bw_ctx) != NULL && \
1883 (bw_ctx)->buf != NULL && \
1884 ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \
1885 ((bw_ctx)->p != NULL && \
1886 (bw_ctx)->p_base != NULL && \
1887 (bw_ctx)->p_limit != NULL && \
1888 (bw_ctx)->p_limit >= (bw_ctx)->p_base && \
1889 (bw_ctx)->p >= (bw_ctx)->p_base && \
1890 (bw_ctx)->p <= (bw_ctx)->p_limit)))
1891#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \
1892 DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \
1893 } while (0)
1894
1895/* Working with the pointer and current size. */
1896
1897#define DUK_BW_GET_PTR(thr,bw_ctx) \
1898 ((bw_ctx)->p)
1899#define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \
1900 (bw_ctx)->p = (ptr); \
1901 } while (0)
1902#define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \
1903 (bw_ctx)->p += (delta); \
1904 } while (0)
1905#define DUK_BW_GET_BASEPTR(thr,bw_ctx) \
1906 ((bw_ctx)->p_base)
1907#define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \
1908 ((bw_ctx)->p_limit)
1909#define DUK_BW_GET_SIZE(thr,bw_ctx) \
1910 ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base))
1911#define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \
1912 DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
1913 (bw_ctx)->p = (bw_ctx)->p_base + (sz); \
1914 } while (0)
1915#define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \
1916 /* Reset to zero size, keep current limit. */ \
1917 (bw_ctx)->p = (bw_ctx)->p_base; \
1918 } while (0)
1919#define DUK_BW_GET_BUFFER(thr,bw_ctx) \
1920 ((bw_ctx)->buf)
1921
1922/* Ensuring (reserving) space. */
1923
1924#define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \
1925 duk_size_t duk__sz, duk__space; \
1926 DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \
1927 duk__sz = (sz); \
1928 duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \
1929 if (duk__space < duk__sz) { \
1930 (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \
1931 } \
1932 } while (0)
1933/* NOTE: Multiple evaluation of 'ptr' in this macro. */
1934/* XXX: Rework to use an always-inline function? */
1935#define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \
1936 (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \
1937 (ptr) : \
1938 ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz))))
1939#define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \
1940 DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p)
1941#define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \
1942 (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \
1943 DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz)))
1944#define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \
1945 DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \
1946 } while (0)
1947
1948/* Miscellaneous. */
1949
1950#define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \
1951 (bw_ctx)->p = (ptr); \
1952 duk_bw_compact((thr), (bw_ctx)); \
1953 } while (0)
1954
1955/* Fast write calls which assume you control the spare beforehand.
1956 * Multibyte write variants exist and use a temporary write pointer
1957 * because byte writes alias with anything: with a stored pointer
1958 * explicit pointer load/stores get generated (e.g. gcc -Os).
1959 */
1960
1961#define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \
1962 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \
1963 *(bw_ctx)->p++ = (duk_uint8_t) (val); \
1964 } while (0)
1965#define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \
1966 duk_uint8_t *duk__p; \
1967 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \
1968 duk__p = (bw_ctx)->p; \
1969 *duk__p++ = (duk_uint8_t) (val1); \
1970 *duk__p++ = (duk_uint8_t) (val2); \
1971 (bw_ctx)->p = duk__p; \
1972 } while (0)
1973#define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \
1974 duk_uint8_t *duk__p; \
1975 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \
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 (bw_ctx)->p = duk__p; \
1981 } while (0)
1982#define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
1983 duk_uint8_t *duk__p; \
1984 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \
1985 duk__p = (bw_ctx)->p; \
1986 *duk__p++ = (duk_uint8_t) (val1); \
1987 *duk__p++ = (duk_uint8_t) (val2); \
1988 *duk__p++ = (duk_uint8_t) (val3); \
1989 *duk__p++ = (duk_uint8_t) (val4); \
1990 (bw_ctx)->p = duk__p; \
1991 } while (0)
1992#define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
1993 duk_uint8_t *duk__p; \
1994 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \
1995 duk__p = (bw_ctx)->p; \
1996 *duk__p++ = (duk_uint8_t) (val1); \
1997 *duk__p++ = (duk_uint8_t) (val2); \
1998 *duk__p++ = (duk_uint8_t) (val3); \
1999 *duk__p++ = (duk_uint8_t) (val4); \
2000 *duk__p++ = (duk_uint8_t) (val5); \
2001 (bw_ctx)->p = duk__p; \
2002 } while (0)
2003#define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2004 duk_uint8_t *duk__p; \
2005 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \
2006 duk__p = (bw_ctx)->p; \
2007 *duk__p++ = (duk_uint8_t) (val1); \
2008 *duk__p++ = (duk_uint8_t) (val2); \
2009 *duk__p++ = (duk_uint8_t) (val3); \
2010 *duk__p++ = (duk_uint8_t) (val4); \
2011 *duk__p++ = (duk_uint8_t) (val5); \
2012 *duk__p++ = (duk_uint8_t) (val6); \
2013 (bw_ctx)->p = duk__p; \
2014 } while (0)
2015#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
2016 duk_ucodepoint_t duk__cp; \
2017 duk_small_int_t duk__enc_len; \
2018 duk__cp = (cp); \
2019 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
2020 duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
2021 (bw_ctx)->p += duk__enc_len; \
2022 } while (0)
2023#define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \
2024 duk_ucodepoint_t duk__cp; \
2025 duk_small_int_t duk__enc_len; \
2026 duk__cp = (duk_ucodepoint_t) (cp); \
2027 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \
2028 duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \
2029 (bw_ctx)->p += duk__enc_len; \
2030 } while (0)
2031/* XXX: add temporary duk__p pointer here too; sharing */
2032#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
2033 const void *duk__valptr; \
2034 duk_size_t duk__valsz; \
2035 duk__valptr = (const void *) (valptr); \
2036 duk__valsz = (duk_size_t) (valsz); \
2037 DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2038 (bw_ctx)->p += duk__valsz; \
2039 } while (0)
2040#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
2041 const duk_uint8_t *duk__val; \
2042 duk_size_t duk__val_len; \
2043 duk__val = (const duk_uint8_t *) (val); \
2044 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2045 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2046 (bw_ctx)->p += duk__val_len; \
2047 } while (0)
2048#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
2049 duk_size_t duk__val_len; \
2050 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2051 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2052 (bw_ctx)->p += duk__val_len; \
2053 } while (0)
2054#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
2055 duk_size_t duk__val_len; \
2056 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2057 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2058 (bw_ctx)->p += duk__val_len; \
2059 } while (0)
2060#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2061 duk_size_t duk__val_len; \
2062 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2063 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2064 (bw_ctx)->p += duk__val_len; \
2065 } while (0)
2066#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2067 duk_size_t duk__val_len; \
2068 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2069 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2070 (bw_ctx)->p += duk__val_len; \
2071 } while (0)
2072
2073/* Append bytes from a slice already in the buffer. */
2074#define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \
2075 duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len))
2076
2077/* Insert bytes in the middle of the buffer from an external buffer. */
2078#define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \
2079 duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len))
2080
2081/* Insert bytes in the middle of the buffer from a slice already
2082 * in the buffer. Source offset is interpreted "before" the operation.
2083 */
2084#define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \
2085 duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len))
2086
2087/* Insert a reserved area somewhere in the buffer; caller fills it.
2088 * Evaluates to a (duk_uint_t *) pointing to the start of the reserved
2089 * area for convenience.
2090 */
2091#define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \
2092 duk_bw_insert_raw_area((thr), (bw), (off), (len))
2093
2094/* Remove a slice from inside buffer. */
2095#define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \
2096 duk_bw_remove_raw_slice((thr), (bw), (off), (len))
2097
2098/* Safe write calls which will ensure space first. */
2099
2100#define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \
2101 DUK_BW_ENSURE((thr), (bw_ctx), 1); \
2102 DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \
2103 } while (0)
2104#define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \
2105 DUK_BW_ENSURE((thr), (bw_ctx), 2); \
2106 DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \
2107 } while (0)
2108#define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2109 DUK_BW_ENSURE((thr), (bw_ctx), 3); \
2110 DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \
2111 } while (0)
2112#define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2113 DUK_BW_ENSURE((thr), (bw_ctx), 4); \
2114 DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \
2115 } while (0)
2116#define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2117 DUK_BW_ENSURE((thr), (bw_ctx), 5); \
2118 DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \
2119 } while (0)
2120#define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2121 DUK_BW_ENSURE((thr), (bw_ctx), 6); \
2122 DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \
2123 } while (0)
2124#define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \
2125 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \
2126 DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \
2127 } while (0)
2128#define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \
2129 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \
2130 DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
2131 } while (0)
2132/* XXX: add temporary duk__p pointer here too; sharing */
2133#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
2134 const void *duk__valptr; \
2135 duk_size_t duk__valsz; \
2136 duk__valptr = (const void *) (valptr); \
2137 duk__valsz = (duk_size_t) (valsz); \
2138 DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
2139 DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2140 (bw_ctx)->p += duk__valsz; \
2141 } while (0)
2142#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
2143 const duk_uint8_t *duk__val; \
2144 duk_size_t duk__val_len; \
2145 duk__val = (const duk_uint8_t *) (val); \
2146 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2147 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2148 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2149 (bw_ctx)->p += duk__val_len; \
2150 } while (0)
2151#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
2152 duk_size_t duk__val_len; \
2153 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2154 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2155 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2156 (bw_ctx)->p += duk__val_len; \
2157 } while (0)
2158#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
2159 duk_size_t duk__val_len; \
2160 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2161 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2162 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2163 (bw_ctx)->p += duk__val_len; \
2164 } while (0)
2165#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2166 duk_size_t duk__val_len; \
2167 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2168 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2169 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2170 (bw_ctx)->p += duk__val_len; \
2171 } while (0)
2172#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2173 duk_size_t duk__val_len; \
2174 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2175 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2176 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2177 (bw_ctx)->p += duk__val_len; \
2178 } while (0)
2179
2180#define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \
2181 duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len))
2182#define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \
2183 duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len))
2184#define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \
2185 duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len))
2186#define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \
2187 /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \
2188 duk_bw_insert_ensure_area((thr), (bw), (off), (len))
2189#define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \
2190 /* No difference between raw/ensure because the buffer shrinks. */ \
2191 DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len))
2192
2193/*
2194 * Externs and prototypes
2195 */
2196
2197#if !defined(DUK_SINGLE_FILE)
2198DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
2199DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
2200DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
2201#if defined(DUK_USE_HEX_FASTPATH)
2202DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
2203DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
2204#endif
2205#if defined(DUK_USE_BASE64_FASTPATH)
2206DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64];
2207DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
2208#endif
2209#endif /* !DUK_SINGLE_FILE */
2210
2211/* Note: assumes that duk_util_probe_steps size is 32 */
2212#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
2213#if !defined(DUK_SINGLE_FILE)
2214DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
2215#endif /* !DUK_SINGLE_FILE */
2216#endif
2217
2218#if defined(DUK_USE_STRHASH_DENSE)
2219DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
2220#endif
2221
2222#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
2223DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
2224#endif
2225
2226DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
2227DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
2228DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
2229
2230DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
2231DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
2232
2233DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
2234DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
2235
2236DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
2237DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
2238DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz);
2239DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
2240DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2241DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2242DUK_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);
2243DUK_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);
2244DUK_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);
2245DUK_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);
2246DUK_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);
2247DUK_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);
2248DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
2249/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
2250
2251DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
2252DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
2253DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
2254DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
2255DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
2256DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
2257
2258#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
2259DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
2260#endif
2261
2262#endif /* DUK_UTIL_H_INCLUDED */
2263#line 1 "duk_strings.h"
2264/*
2265 * Shared error messages: declarations and macros
2266 *
2267 * Error messages are accessed through macros with fine-grained, explicit
2268 * error message distinctions. Concrete error messages are selected by the
2269 * macros and multiple macros can map to the same concrete string to save
2270 * on code footprint. This allows flexible footprint/verbosity tuning with
2271 * minimal code impact. There are a few limitations to this approach:
2272 * (1) switching between plain messages and format strings doesn't work
2273 * conveniently, and (2) conditional strings are a bit awkward to handle.
2274 *
2275 * Because format strings behave differently in the call site (they need to
2276 * be followed by format arguments), they have a special prefix (DUK_STR_FMT_
2277 * and duk_str_fmt_).
2278 *
2279 * On some compilers using explicit shared strings is preferable; on others
2280 * it may be better to use straight literals because the compiler will combine
2281 * them anyway, and such strings won't end up unnecessarily in a symbol table.
2282 */
2283
2284#ifndef DUK_ERRMSG_H_INCLUDED
2285#define DUK_ERRMSG_H_INCLUDED
2286
2287#define DUK_STR_INTERNAL_ERROR duk_str_internal_error
2288#define DUK_STR_INVALID_COUNT duk_str_invalid_count
2289#define DUK_STR_INVALID_CALL_ARGS duk_str_invalid_call_args
2290#define DUK_STR_NOT_CONSTRUCTABLE duk_str_not_constructable
2291#define DUK_STR_NOT_CALLABLE duk_str_not_callable
2292#define DUK_STR_NOT_EXTENSIBLE duk_str_not_extensible
2293#define DUK_STR_NOT_WRITABLE duk_str_not_writable
2294#define DUK_STR_NOT_CONFIGURABLE duk_str_not_configurable
2295
2296#if !defined(DUK_SINGLE_FILE)
2297DUK_INTERNAL_DECL const char *duk_str_internal_error;
2298DUK_INTERNAL_DECL const char *duk_str_invalid_count;
2299DUK_INTERNAL_DECL const char *duk_str_invalid_call_args;
2300DUK_INTERNAL_DECL const char *duk_str_not_constructable;
2301DUK_INTERNAL_DECL const char *duk_str_not_callable;
2302DUK_INTERNAL_DECL const char *duk_str_not_extensible;
2303DUK_INTERNAL_DECL const char *duk_str_not_writable;
2304DUK_INTERNAL_DECL const char *duk_str_not_configurable;
2305#endif /* !DUK_SINGLE_FILE */
2306
2307#define DUK_STR_INVALID_CONTEXT duk_str_invalid_context
2308#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args
2309#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack
2310#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type
2311#define DUK_STR_NOT_NULL duk_str_unexpected_type
2312#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type
2313#define DUK_STR_NOT_NUMBER duk_str_unexpected_type
2314#define DUK_STR_NOT_STRING duk_str_unexpected_type
2315#define DUK_STR_NOT_OBJECT duk_str_unexpected_type
2316#define DUK_STR_NOT_POINTER duk_str_unexpected_type
2317#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */
2318#define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type
2319#define DUK_STR_NOT_THREAD duk_str_unexpected_type
2320#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type
2321#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type
2322#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type
2323#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type
2324#define DUK_STR_NOT_REGEXP duk_str_unexpected_type
2325#define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed
2326#define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range
2327#define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible
2328#define DUK_STR_STRING_TOO_LONG duk_str_string_too_long
2329#define DUK_STR_BUFFER_TOO_LONG duk_str_buffer_too_long
2330#define DUK_STR_SPRINTF_TOO_LONG duk_str_sprintf_too_long
2331#define DUK_STR_ALLOC_FAILED duk_str_alloc_failed
2332#define DUK_STR_POP_TOO_MANY duk_str_pop_too_many
2333#define DUK_STR_WRONG_BUFFER_TYPE duk_str_wrong_buffer_type
2334#define DUK_STR_ENCODE_FAILED duk_str_encode_failed
2335#define DUK_STR_DECODE_FAILED duk_str_decode_failed
2336#define DUK_STR_NO_SOURCECODE duk_str_no_sourcecode
2337#define DUK_STR_CONCAT_RESULT_TOO_LONG duk_str_concat_result_too_long
2338#define DUK_STR_UNIMPLEMENTED duk_str_unimplemented
2339#define DUK_STR_UNSUPPORTED duk_str_unsupported
2340#define DUK_STR_ARRAY_LENGTH_OVER_2G duk_str_array_length_over_2g
2341
2342#if !defined(DUK_SINGLE_FILE)
2343DUK_INTERNAL_DECL const char *duk_str_invalid_context;
2344DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack;
2345DUK_INTERNAL_DECL const char *duk_str_not_buffer;
2346DUK_INTERNAL_DECL const char *duk_str_unexpected_type;
2347DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed;
2348DUK_INTERNAL_DECL const char *duk_str_number_outside_range;
2349DUK_INTERNAL_DECL const char *duk_str_not_object_coercible;
2350DUK_INTERNAL_DECL const char *duk_str_string_too_long;
2351DUK_INTERNAL_DECL const char *duk_str_buffer_too_long;
2352DUK_INTERNAL_DECL const char *duk_str_sprintf_too_long;
2353DUK_INTERNAL_DECL const char *duk_str_alloc_failed;
2354DUK_INTERNAL_DECL const char *duk_str_pop_too_many;
2355DUK_INTERNAL_DECL const char *duk_str_wrong_buffer_type;
2356DUK_INTERNAL_DECL const char *duk_str_encode_failed;
2357DUK_INTERNAL_DECL const char *duk_str_decode_failed;
2358DUK_INTERNAL_DECL const char *duk_str_no_sourcecode;
2359DUK_INTERNAL_DECL const char *duk_str_concat_result_too_long;
2360DUK_INTERNAL_DECL const char *duk_str_unimplemented;
2361DUK_INTERNAL_DECL const char *duk_str_unsupported;
2362DUK_INTERNAL_DECL const char *duk_str_array_length_over_2g;
2363#endif /* !DUK_SINGLE_FILE */
2364
2365#define DUK_STR_FMT_PTR duk_str_fmt_ptr
2366#define DUK_STR_FMT_INVALID_JSON duk_str_fmt_invalid_json
2367#define DUK_STR_JSONDEC_RECLIMIT duk_str_jsondec_reclimit
2368#define DUK_STR_JSONENC_RECLIMIT duk_str_jsonenc_reclimit
2369#define DUK_STR_CYCLIC_INPUT duk_str_cyclic_input
2370
2371#if !defined(DUK_SINGLE_FILE)
2372DUK_INTERNAL_DECL const char *duk_str_fmt_ptr;
2373DUK_INTERNAL_DECL const char *duk_str_fmt_invalid_json;
2374DUK_INTERNAL_DECL const char *duk_str_jsondec_reclimit;
2375DUK_INTERNAL_DECL const char *duk_str_jsonenc_reclimit;
2376DUK_INTERNAL_DECL const char *duk_str_cyclic_input;
2377#endif /* !DUK_SINGLE_FILE */
2378
2379#define DUK_STR_PROXY_REVOKED duk_str_proxy_revoked
2380#define DUK_STR_INVALID_BASE duk_str_invalid_base
2381#define DUK_STR_STRICT_CALLER_READ duk_str_strict_caller_read
2382#define DUK_STR_PROXY_REJECTED duk_str_proxy_rejected
2383#define DUK_STR_INVALID_ARRAY_LENGTH duk_str_invalid_array_length
2384#define DUK_STR_ARRAY_LENGTH_WRITE_FAILED duk_str_array_length_write_failed
2385#define DUK_STR_ARRAY_LENGTH_NOT_WRITABLE duk_str_array_length_not_writable
2386#define DUK_STR_SETTER_UNDEFINED duk_str_setter_undefined
2387#define DUK_STR_REDEFINE_VIRT_PROP duk_str_redefine_virt_prop
2388#define DUK_STR_INVALID_DESCRIPTOR duk_str_invalid_descriptor
2389#define DUK_STR_PROPERTY_IS_VIRTUAL duk_str_property_is_virtual
2390
2391#if !defined(DUK_SINGLE_FILE)
2392DUK_INTERNAL_DECL const char *duk_str_proxy_revoked;
2393DUK_INTERNAL_DECL const char *duk_str_invalid_base;
2394DUK_INTERNAL_DECL const char *duk_str_strict_caller_read;
2395DUK_INTERNAL_DECL const char *duk_str_proxy_rejected;
2396DUK_INTERNAL_DECL const char *duk_str_invalid_array_length;
2397DUK_INTERNAL_DECL const char *duk_str_array_length_write_failed;
2398DUK_INTERNAL_DECL const char *duk_str_array_length_not_writable;
2399DUK_INTERNAL_DECL const char *duk_str_setter_undefined;
2400DUK_INTERNAL_DECL const char *duk_str_redefine_virt_prop;
2401DUK_INTERNAL_DECL const char *duk_str_invalid_descriptor;
2402DUK_INTERNAL_DECL const char *duk_str_property_is_virtual;
2403#endif /* !DUK_SINGLE_FILE */
2404
2405#define DUK_STR_PARSE_ERROR duk_str_parse_error
2406#define DUK_STR_DUPLICATE_LABEL duk_str_duplicate_label
2407#define DUK_STR_INVALID_LABEL duk_str_invalid_label
2408#define DUK_STR_INVALID_ARRAY_LITERAL duk_str_invalid_array_literal
2409#define DUK_STR_INVALID_OBJECT_LITERAL duk_str_invalid_object_literal
2410#define DUK_STR_INVALID_VAR_DECLARATION duk_str_invalid_var_declaration
2411#define DUK_STR_CANNOT_DELETE_IDENTIFIER duk_str_cannot_delete_identifier
2412#define DUK_STR_INVALID_EXPRESSION duk_str_invalid_expression
2413#define DUK_STR_INVALID_LVALUE duk_str_invalid_lvalue
2414#define DUK_STR_EXPECTED_IDENTIFIER duk_str_expected_identifier
2415#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED duk_str_empty_expr_not_allowed
2416#define DUK_STR_INVALID_FOR duk_str_invalid_for
2417#define DUK_STR_INVALID_SWITCH duk_str_invalid_switch
2418#define DUK_STR_INVALID_BREAK_CONT_LABEL duk_str_invalid_break_cont_label
2419#define DUK_STR_INVALID_RETURN duk_str_invalid_return
2420#define DUK_STR_INVALID_TRY duk_str_invalid_try
2421#define DUK_STR_INVALID_THROW duk_str_invalid_throw
2422#define DUK_STR_WITH_IN_STRICT_MODE duk_str_with_in_strict_mode
2423#define DUK_STR_FUNC_STMT_NOT_ALLOWED duk_str_func_stmt_not_allowed
2424#define DUK_STR_UNTERMINATED_STMT duk_str_unterminated_stmt
2425#define DUK_STR_INVALID_ARG_NAME duk_str_invalid_arg_name
2426#define DUK_STR_INVALID_FUNC_NAME duk_str_invalid_func_name
2427#define DUK_STR_INVALID_GETSET_NAME duk_str_invalid_getset_name
2428#define DUK_STR_FUNC_NAME_REQUIRED duk_str_func_name_required
2429
2430#if !defined(DUK_SINGLE_FILE)
2431DUK_INTERNAL_DECL const char *duk_str_parse_error;
2432DUK_INTERNAL_DECL const char *duk_str_duplicate_label;
2433DUK_INTERNAL_DECL const char *duk_str_invalid_label;
2434DUK_INTERNAL_DECL const char *duk_str_invalid_array_literal;
2435DUK_INTERNAL_DECL const char *duk_str_invalid_object_literal;
2436DUK_INTERNAL_DECL const char *duk_str_invalid_var_declaration;
2437DUK_INTERNAL_DECL const char *duk_str_cannot_delete_identifier;
2438DUK_INTERNAL_DECL const char *duk_str_invalid_expression;
2439DUK_INTERNAL_DECL const char *duk_str_invalid_lvalue;
2440DUK_INTERNAL_DECL const char *duk_str_expected_identifier;
2441DUK_INTERNAL_DECL const char *duk_str_empty_expr_not_allowed;
2442DUK_INTERNAL_DECL const char *duk_str_invalid_for;
2443DUK_INTERNAL_DECL const char *duk_str_invalid_switch;
2444DUK_INTERNAL_DECL const char *duk_str_invalid_break_cont_label;
2445DUK_INTERNAL_DECL const char *duk_str_invalid_return;
2446DUK_INTERNAL_DECL const char *duk_str_invalid_try;
2447DUK_INTERNAL_DECL const char *duk_str_invalid_throw;
2448DUK_INTERNAL_DECL const char *duk_str_with_in_strict_mode;
2449DUK_INTERNAL_DECL const char *duk_str_func_stmt_not_allowed;
2450DUK_INTERNAL_DECL const char *duk_str_unterminated_stmt;
2451DUK_INTERNAL_DECL const char *duk_str_invalid_arg_name;
2452DUK_INTERNAL_DECL const char *duk_str_invalid_func_name;
2453DUK_INTERNAL_DECL const char *duk_str_invalid_getset_name;
2454DUK_INTERNAL_DECL const char *duk_str_func_name_required;
2455#endif /* !DUK_SINGLE_FILE */
2456
2457#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM duk_str_invalid_quantifier_no_atom
2458#define DUK_STR_INVALID_QUANTIFIER_VALUES duk_str_invalid_quantifier_values
2459#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES duk_str_quantifier_too_many_copies
2460#define DUK_STR_UNEXPECTED_CLOSING_PAREN duk_str_unexpected_closing_paren
2461#define DUK_STR_UNEXPECTED_END_OF_PATTERN duk_str_unexpected_end_of_pattern
2462#define DUK_STR_UNEXPECTED_REGEXP_TOKEN duk_str_unexpected_regexp_token
2463#define DUK_STR_INVALID_REGEXP_FLAGS duk_str_invalid_regexp_flags
2464#define DUK_STR_INVALID_BACKREFS duk_str_invalid_backrefs
2465
2466#if !defined(DUK_SINGLE_FILE)
2467DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_no_atom;
2468DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_values;
2469DUK_INTERNAL_DECL const char *duk_str_quantifier_too_many_copies;
2470DUK_INTERNAL_DECL const char *duk_str_unexpected_closing_paren;
2471DUK_INTERNAL_DECL const char *duk_str_unexpected_end_of_pattern;
2472DUK_INTERNAL_DECL const char *duk_str_unexpected_regexp_token;
2473DUK_INTERNAL_DECL const char *duk_str_invalid_regexp_flags;
2474DUK_INTERNAL_DECL const char *duk_str_invalid_backrefs;
2475#endif /* !DUK_SINGLE_FILE */
2476
2477#define DUK_STR_VALSTACK_LIMIT duk_str_valstack_limit
2478#define DUK_STR_CALLSTACK_LIMIT duk_str_callstack_limit
2479#define DUK_STR_CATCHSTACK_LIMIT duk_str_catchstack_limit
2480#define DUK_STR_PROTOTYPE_CHAIN_LIMIT duk_str_prototype_chain_limit
2481#define DUK_STR_BOUND_CHAIN_LIMIT duk_str_bound_chain_limit
2482#define DUK_STR_C_CALLSTACK_LIMIT duk_str_c_callstack_limit
2483#define DUK_STR_COMPILER_RECURSION_LIMIT duk_str_compiler_recursion_limit
2484#define DUK_STR_BYTECODE_LIMIT duk_str_bytecode_limit
2485#define DUK_STR_REG_LIMIT duk_str_reg_limit
2486#define DUK_STR_TEMP_LIMIT duk_str_temp_limit
2487#define DUK_STR_CONST_LIMIT duk_str_const_limit
2488#define DUK_STR_FUNC_LIMIT duk_str_func_limit
2489#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT duk_str_regexp_compiler_recursion_limit
2490#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT duk_str_regexp_executor_recursion_limit
2491#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT duk_str_regexp_executor_step_limit
2492
2493#if !defined(DUK_SINGLE_FILE)
2494DUK_INTERNAL_DECL const char *duk_str_valstack_limit;
2495DUK_INTERNAL_DECL const char *duk_str_callstack_limit;
2496DUK_INTERNAL_DECL const char *duk_str_catchstack_limit;
2497DUK_INTERNAL_DECL const char *duk_str_prototype_chain_limit;
2498DUK_INTERNAL_DECL const char *duk_str_bound_chain_limit;
2499DUK_INTERNAL_DECL const char *duk_str_c_callstack_limit;
2500DUK_INTERNAL_DECL const char *duk_str_compiler_recursion_limit;
2501DUK_INTERNAL_DECL const char *duk_str_bytecode_limit;
2502DUK_INTERNAL_DECL const char *duk_str_reg_limit;
2503DUK_INTERNAL_DECL const char *duk_str_temp_limit;
2504DUK_INTERNAL_DECL const char *duk_str_const_limit;
2505DUK_INTERNAL_DECL const char *duk_str_func_limit;
2506DUK_INTERNAL_DECL const char *duk_str_regexp_compiler_recursion_limit;
2507DUK_INTERNAL_DECL const char *duk_str_regexp_executor_recursion_limit;
2508DUK_INTERNAL_DECL const char *duk_str_regexp_executor_step_limit;
2509#endif /* !DUK_SINGLE_FILE */
2510
2511#if !defined(DUK_SINGLE_FILE)
2512DUK_INTERNAL_DECL const char *duk_str_anon;
2513#endif /* !DUK_SINGLE_FILE */
2514
2515#endif /* DUK_ERRMSG_H_INCLUDED */
2516#line 1 "duk_js_bytecode.h"
2517/*
2518 * Ecmascript bytecode
2519 */
2520
2521#ifndef DUK_JS_BYTECODE_H_INCLUDED
2522#define DUK_JS_BYTECODE_H_INCLUDED
2523
2524/*
2525 * Logical instruction layout
2526 * ==========================
2527 *
2528 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
2529 * !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!
2530 * +---------------------------------------------------+-----------+
2531 * ! C ! B ! A ! OP !
2532 * +---------------------------------------------------+-----------+
2533 *
2534 * OP (6 bits): opcode (DUK_OP_*), access should be fastest
2535 * A (8 bits): typically a target register number
2536 * B (9 bits): typically first source register/constant number
2537 * C (9 bits): typically second source register/constant number
2538 *
2539 * Some instructions combine BC or ABC together for larger parameter values.
2540 * Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode
2541 * specific bias. B and C may denote a register or a constant, see
2542 * DUK_BC_ISREG() and DUK_BC_ISCONST().
2543 *
2544 * Note: macro naming is a bit misleading, e.g. "ABC" in macro name but
2545 * the field layout is logically "CBA".
2546 */
2547
2548typedef duk_uint32_t duk_instr_t;
2549
2550#define DUK_DEC_OP(x) ((x) & 0x3fUL)
2551#define DUK_DEC_A(x) (((x) >> 6) & 0xffUL)
2552#define DUK_DEC_B(x) (((x) >> 14) & 0x1ffUL)
2553#define DUK_DEC_C(x) (((x) >> 23) & 0x1ffUL)
2554#define DUK_DEC_BC(x) (((x) >> 14) & 0x3ffffUL)
2555#define DUK_DEC_ABC(x) (((x) >> 6) & 0x3ffffffUL)
2556
2557#define DUK_ENC_OP(op) ((duk_instr_t) (op))
2558#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \
2559 (((duk_instr_t) (abc)) << 6) | \
2560 ((duk_instr_t) (op)) \
2561 ))
2562#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \
2563 (((duk_instr_t) (bc)) << 14) | \
2564 (((duk_instr_t) (a)) << 6) | \
2565 ((duk_instr_t) (op)) \
2566 ))
2567#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \
2568 (((duk_instr_t) (c)) << 23) | \
2569 (((duk_instr_t) (b)) << 14) | \
2570 (((duk_instr_t) (a)) << 6) | \
2571 ((duk_instr_t) (op)) \
2572 ))
2573#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C(op,a,b,0)
2574#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C(op,a,0,0)
2575
2576/* Constants should be signed so that signed arithmetic involving them
2577 * won't cause values to be coerced accidentally to unsigned.
2578 */
2579#define DUK_BC_OP_MIN 0
2580#define DUK_BC_OP_MAX 0x3fL
2581#define DUK_BC_A_MIN 0
2582#define DUK_BC_A_MAX 0xffL
2583#define DUK_BC_B_MIN 0
2584#define DUK_BC_B_MAX 0x1ffL
2585#define DUK_BC_C_MIN 0
2586#define DUK_BC_C_MAX 0x1ffL
2587#define DUK_BC_BC_MIN 0
2588#define DUK_BC_BC_MAX 0x3ffffL
2589#define DUK_BC_ABC_MIN 0
2590#define DUK_BC_ABC_MAX 0x3ffffffL
2591#define DUK_BC_EXTRAOP_MIN DUK_BC_A_MIN
2592#define DUK_BC_EXTRAOP_MAX DUK_BC_A_MAX
2593
2594#define DUK_OP_LDREG 0
2595#define DUK_OP_STREG 1
2596#define DUK_OP_LDCONST 2
2597#define DUK_OP_LDINT 3
2598#define DUK_OP_LDINTX 4
2599#define DUK_OP_MPUTOBJ 5
2600#define DUK_OP_MPUTOBJI 6
2601#define DUK_OP_MPUTARR 7
2602#define DUK_OP_MPUTARRI 8
2603#define DUK_OP_NEW 9
2604#define DUK_OP_NEWI 10
2605#define DUK_OP_REGEXP 11
2606#define DUK_OP_CSREG 12
2607#define DUK_OP_CSREGI 13
2608#define DUK_OP_GETVAR 14
2609#define DUK_OP_PUTVAR 15
2610#define DUK_OP_DECLVAR 16
2611#define DUK_OP_DELVAR 17
2612#define DUK_OP_CSVAR 18
2613#define DUK_OP_CSVARI 19
2614#define DUK_OP_CLOSURE 20
2615#define DUK_OP_GETPROP 21
2616#define DUK_OP_PUTPROP 22
2617#define DUK_OP_DELPROP 23
2618#define DUK_OP_CSPROP 24
2619#define DUK_OP_CSPROPI 25
2620#define DUK_OP_ADD 26
2621#define DUK_OP_SUB 27
2622#define DUK_OP_MUL 28
2623#define DUK_OP_DIV 29
2624#define DUK_OP_MOD 30
2625#define DUK_OP_BAND 31
2626#define DUK_OP_BOR 32
2627#define DUK_OP_BXOR 33
2628#define DUK_OP_BASL 34
2629#define DUK_OP_BLSR 35
2630#define DUK_OP_BASR 36
2631#define DUK_OP_EQ 37
2632#define DUK_OP_NEQ 38
2633#define DUK_OP_SEQ 39
2634#define DUK_OP_SNEQ 40
2635#define DUK_OP_GT 41
2636#define DUK_OP_GE 42
2637#define DUK_OP_LT 43
2638#define DUK_OP_LE 44
2639#define DUK_OP_IF 45
2640#define DUK_OP_JUMP 46
2641#define DUK_OP_RETURN 47
2642#define DUK_OP_CALL 48
2643#define DUK_OP_CALLI 49
2644#define DUK_OP_TRYCATCH 50
2645#define DUK_OP_EXTRA 51
2646#define DUK_OP_PREINCR 52 /* pre/post opcode values have constraints, */
2647#define DUK_OP_PREDECR 53 /* see duk_js_executor.c */
2648#define DUK_OP_POSTINCR 54
2649#define DUK_OP_POSTDECR 55
2650#define DUK_OP_PREINCV 56
2651#define DUK_OP_PREDECV 57
2652#define DUK_OP_POSTINCV 58
2653#define DUK_OP_POSTDECV 59
2654#define DUK_OP_PREINCP 60
2655#define DUK_OP_PREDECP 61
2656#define DUK_OP_POSTINCP 62
2657#define DUK_OP_POSTDECP 63
2658#define DUK_OP_NONE 64 /* dummy value used as marker */
2659
2660/* DUK_OP_EXTRA, sub-operation in A */
2661#define DUK_EXTRAOP_NOP 0
2662#define DUK_EXTRAOP_INVALID 1
2663#define DUK_EXTRAOP_LDTHIS 2
2664#define DUK_EXTRAOP_LDUNDEF 3
2665#define DUK_EXTRAOP_LDNULL 4
2666#define DUK_EXTRAOP_LDTRUE 5
2667#define DUK_EXTRAOP_LDFALSE 6
2668#define DUK_EXTRAOP_NEWOBJ 7
2669#define DUK_EXTRAOP_NEWARR 8
2670#define DUK_EXTRAOP_SETALEN 9
2671#define DUK_EXTRAOP_TYPEOF 10
2672#define DUK_EXTRAOP_TYPEOFID 11
2673#define DUK_EXTRAOP_INITENUM 12
2674#define DUK_EXTRAOP_NEXTENUM 13
2675#define DUK_EXTRAOP_INITSET 14
2676#define DUK_EXTRAOP_INITSETI 15
2677#define DUK_EXTRAOP_INITGET 16
2678#define DUK_EXTRAOP_INITGETI 17
2679#define DUK_EXTRAOP_ENDTRY 18
2680#define DUK_EXTRAOP_ENDCATCH 19
2681#define DUK_EXTRAOP_ENDFIN 20
2682#define DUK_EXTRAOP_THROW 21
2683#define DUK_EXTRAOP_INVLHS 22
2684#define DUK_EXTRAOP_UNM 23
2685#define DUK_EXTRAOP_UNP 24
2686#define DUK_EXTRAOP_DEBUGGER 25
2687#define DUK_EXTRAOP_BREAK 26
2688#define DUK_EXTRAOP_CONTINUE 27
2689#define DUK_EXTRAOP_BNOT 28
2690#define DUK_EXTRAOP_LNOT 29
2691#define DUK_EXTRAOP_INSTOF 30
2692#define DUK_EXTRAOP_IN 31
2693#define DUK_EXTRAOP_LABEL 32
2694#define DUK_EXTRAOP_ENDLABEL 33
2695
2696/* DUK_OP_CALL flags in A */
2697#define DUK_BC_CALL_FLAG_TAILCALL (1 << 0)
2698#define DUK_BC_CALL_FLAG_EVALCALL (1 << 1)
2699
2700/* DUK_OP_TRYCATCH flags in A */
2701#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0)
2702#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1)
2703#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2)
2704#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3)
2705
2706/* DUK_OP_RETURN flags in A */
2707#define DUK_BC_RETURN_FLAG_HAVE_RETVAL (1 << 0)
2708
2709/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
2710#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */
2711#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */
2712
2713/* misc constants and helper macros */
2714#define DUK_BC_REGLIMIT 256 /* if B/C is >= this value, refers to a const */
2715#define DUK_BC_ISREG(x) ((x) < DUK_BC_REGLIMIT)
2716#define DUK_BC_ISCONST(x) ((x) >= DUK_BC_REGLIMIT)
2717#define DUK_BC_LDINT_BIAS (1L << 17)
2718#define DUK_BC_LDINTX_SHIFT 18
2719#define DUK_BC_JUMP_BIAS (1L << 25)
2720
2721#endif /* DUK_JS_BYTECODE_H_INCLUDED */
2722#line 1 "duk_lexer.h"
2723/*
2724 * Lexer defines.
2725 */
2726
2727#ifndef DUK_LEXER_H_INCLUDED
2728#define DUK_LEXER_H_INCLUDED
2729
2730typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
2731
2732/*
2733 * A token is interpreted as any possible production of InputElementDiv
2734 * and InputElementRegExp, see E5 Section 7 in its entirety. Note that
2735 * the E5 "Token" production does not cover all actual tokens of the
2736 * language (which is explicitly stated in the specification, Section 7.5).
2737 * Null and boolean literals are defined as part of both ReservedWord
2738 * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here,
2739 * null and boolean values have literal tokens, and are not reserved
2740 * words.
2741 *
2742 * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER.
2743 * The number tokens always have a non-negative value. The unary minus
2744 * operator in "-1.0" is optimized during compilation to yield a single
2745 * negative constant.
2746 *
2747 * Token numbering is free except that reserved words are required to be
2748 * in a continuous range and in a particular order. See genstrings.py.
2749 */
2750
2751#define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx))
2752
2753#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt))
2754
2755#define DUK_LEXER_GETPOINT(ctx,pt) do { (pt)->offset = (ctx)->window[0].offset; \
2756 (pt)->line = (ctx)->window[0].line; } while (0)
2757
2758/* currently 6 characters of lookup are actually needed (duk_lexer.c) */
2759#define DUK_LEXER_WINDOW_SIZE 6
2760#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
2761#define DUK_LEXER_BUFFER_SIZE 64
2762#endif
2763
2764#define DUK_TOK_MINVAL 0
2765
2766/* returned after EOF (infinite amount) */
2767#define DUK_TOK_EOF 0
2768
2769/* identifier names (E5 Section 7.6) */
2770#define DUK_TOK_IDENTIFIER 1
2771
2772/* reserved words: keywords */
2773#define DUK_TOK_START_RESERVED 2
2774#define DUK_TOK_BREAK 2
2775#define DUK_TOK_CASE 3
2776#define DUK_TOK_CATCH 4
2777#define DUK_TOK_CONTINUE 5
2778#define DUK_TOK_DEBUGGER 6
2779#define DUK_TOK_DEFAULT 7
2780#define DUK_TOK_DELETE 8
2781#define DUK_TOK_DO 9
2782#define DUK_TOK_ELSE 10
2783#define DUK_TOK_FINALLY 11
2784#define DUK_TOK_FOR 12
2785#define DUK_TOK_FUNCTION 13
2786#define DUK_TOK_IF 14
2787#define DUK_TOK_IN 15
2788#define DUK_TOK_INSTANCEOF 16
2789#define DUK_TOK_NEW 17
2790#define DUK_TOK_RETURN 18
2791#define DUK_TOK_SWITCH 19
2792#define DUK_TOK_THIS 20
2793#define DUK_TOK_THROW 21
2794#define DUK_TOK_TRY 22
2795#define DUK_TOK_TYPEOF 23
2796#define DUK_TOK_VAR 24
2797#define DUK_TOK_CONST 25
2798#define DUK_TOK_VOID 26
2799#define DUK_TOK_WHILE 27
2800#define DUK_TOK_WITH 28
2801
2802/* reserved words: future reserved words */
2803#define DUK_TOK_CLASS 29
2804#define DUK_TOK_ENUM 30
2805#define DUK_TOK_EXPORT 31
2806#define DUK_TOK_EXTENDS 32
2807#define DUK_TOK_IMPORT 33
2808#define DUK_TOK_SUPER 34
2809
2810/* "null", "true", and "false" are always reserved words.
2811 * Note that "get" and "set" are not!
2812 */
2813#define DUK_TOK_NULL 35
2814#define DUK_TOK_TRUE 36
2815#define DUK_TOK_FALSE 37
2816
2817/* reserved words: additional future reserved words in strict mode */
2818#define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */
2819#define DUK_TOK_IMPLEMENTS 38
2820#define DUK_TOK_INTERFACE 39
2821#define DUK_TOK_LET 40
2822#define DUK_TOK_PACKAGE 41
2823#define DUK_TOK_PRIVATE 42
2824#define DUK_TOK_PROTECTED 43
2825#define DUK_TOK_PUBLIC 44
2826#define DUK_TOK_STATIC 45
2827#define DUK_TOK_YIELD 46
2828
2829#define DUK_TOK_END_RESERVED 47 /* exclusive */
2830
2831/* "get" and "set" are tokens but NOT ReservedWords. They are currently
2832 * parsed and identifiers and these defines are actually now unused.
2833 */
2834#define DUK_TOK_GET 47
2835#define DUK_TOK_SET 48
2836
2837/* punctuators (unlike the spec, also includes "/" and "/=") */
2838#define DUK_TOK_LCURLY 49
2839#define DUK_TOK_RCURLY 50
2840#define DUK_TOK_LBRACKET 51
2841#define DUK_TOK_RBRACKET 52
2842#define DUK_TOK_LPAREN 53
2843#define DUK_TOK_RPAREN 54
2844#define DUK_TOK_PERIOD 55
2845#define DUK_TOK_SEMICOLON 56
2846#define DUK_TOK_COMMA 57
2847#define DUK_TOK_LT 58
2848#define DUK_TOK_GT 59
2849#define DUK_TOK_LE 60
2850#define DUK_TOK_GE 61
2851#define DUK_TOK_EQ 62
2852#define DUK_TOK_NEQ 63
2853#define DUK_TOK_SEQ 64
2854#define DUK_TOK_SNEQ 65
2855#define DUK_TOK_ADD 66
2856#define DUK_TOK_SUB 67
2857#define DUK_TOK_MUL 68
2858#define DUK_TOK_DIV 69
2859#define DUK_TOK_MOD 70
2860#define DUK_TOK_INCREMENT 71
2861#define DUK_TOK_DECREMENT 72
2862#define DUK_TOK_ALSHIFT 73 /* named "arithmetic" because result is signed */
2863#define DUK_TOK_ARSHIFT 74
2864#define DUK_TOK_RSHIFT 75
2865#define DUK_TOK_BAND 76
2866#define DUK_TOK_BOR 77
2867#define DUK_TOK_BXOR 78
2868#define DUK_TOK_LNOT 79
2869#define DUK_TOK_BNOT 80
2870#define DUK_TOK_LAND 81
2871#define DUK_TOK_LOR 82
2872#define DUK_TOK_QUESTION 83
2873#define DUK_TOK_COLON 84
2874#define DUK_TOK_EQUALSIGN 85
2875#define DUK_TOK_ADD_EQ 86
2876#define DUK_TOK_SUB_EQ 87
2877#define DUK_TOK_MUL_EQ 88
2878#define DUK_TOK_DIV_EQ 89
2879#define DUK_TOK_MOD_EQ 90
2880#define DUK_TOK_ALSHIFT_EQ 91
2881#define DUK_TOK_ARSHIFT_EQ 92
2882#define DUK_TOK_RSHIFT_EQ 93
2883#define DUK_TOK_BAND_EQ 94
2884#define DUK_TOK_BOR_EQ 95
2885#define DUK_TOK_BXOR_EQ 96
2886
2887/* literals (E5 Section 7.8), except null, true, false, which are treated
2888 * like reserved words (above).
2889 */
2890#define DUK_TOK_NUMBER 97
2891#define DUK_TOK_STRING 98
2892#define DUK_TOK_REGEXP 99
2893
2894#define DUK_TOK_MAXVAL 99 /* inclusive */
2895
2896/* Convert heap string index to a token (reserved words) */
2897#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
2898
2899/* Sanity check */
2900#if (DUK_TOK_MAXVAL > 255)
2901#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits
2902#endif
2903
2904/* Sanity checks for string and token defines */
2905#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK)
2906#error mismatch in token defines
2907#endif
2908#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE)
2909#error mismatch in token defines
2910#endif
2911#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH)
2912#error mismatch in token defines
2913#endif
2914#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE)
2915#error mismatch in token defines
2916#endif
2917#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER)
2918#error mismatch in token defines
2919#endif
2920#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT)
2921#error mismatch in token defines
2922#endif
2923#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE)
2924#error mismatch in token defines
2925#endif
2926#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO)
2927#error mismatch in token defines
2928#endif
2929#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE)
2930#error mismatch in token defines
2931#endif
2932#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY)
2933#error mismatch in token defines
2934#endif
2935#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR)
2936#error mismatch in token defines
2937#endif
2938#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION)
2939#error mismatch in token defines
2940#endif
2941#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF)
2942#error mismatch in token defines
2943#endif
2944#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN)
2945#error mismatch in token defines
2946#endif
2947#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF)
2948#error mismatch in token defines
2949#endif
2950#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW)
2951#error mismatch in token defines
2952#endif
2953#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN)
2954#error mismatch in token defines
2955#endif
2956#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH)
2957#error mismatch in token defines
2958#endif
2959#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS)
2960#error mismatch in token defines
2961#endif
2962#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW)
2963#error mismatch in token defines
2964#endif
2965#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY)
2966#error mismatch in token defines
2967#endif
2968#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF)
2969#error mismatch in token defines
2970#endif
2971#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR)
2972#error mismatch in token defines
2973#endif
2974#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID)
2975#error mismatch in token defines
2976#endif
2977#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE)
2978#error mismatch in token defines
2979#endif
2980#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH)
2981#error mismatch in token defines
2982#endif
2983#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS)
2984#error mismatch in token defines
2985#endif
2986#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST)
2987#error mismatch in token defines
2988#endif
2989#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM)
2990#error mismatch in token defines
2991#endif
2992#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT)
2993#error mismatch in token defines
2994#endif
2995#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS)
2996#error mismatch in token defines
2997#endif
2998#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT)
2999#error mismatch in token defines
3000#endif
3001#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER)
3002#error mismatch in token defines
3003#endif
3004#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL)
3005#error mismatch in token defines
3006#endif
3007#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE)
3008#error mismatch in token defines
3009#endif
3010#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE)
3011#error mismatch in token defines
3012#endif
3013#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS)
3014#error mismatch in token defines
3015#endif
3016#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE)
3017#error mismatch in token defines
3018#endif
3019#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET)
3020#error mismatch in token defines
3021#endif
3022#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE)
3023#error mismatch in token defines
3024#endif
3025#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE)
3026#error mismatch in token defines
3027#endif
3028#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED)
3029#error mismatch in token defines
3030#endif
3031#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC)
3032#error mismatch in token defines
3033#endif
3034#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC)
3035#error mismatch in token defines
3036#endif
3037#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD)
3038#error mismatch in token defines
3039#endif
3040
3041/* Regexp tokens */
3042#define DUK_RETOK_EOF 0
3043#define DUK_RETOK_DISJUNCTION 1
3044#define DUK_RETOK_QUANTIFIER 2
3045#define DUK_RETOK_ASSERT_START 3
3046#define DUK_RETOK_ASSERT_END 4
3047#define DUK_RETOK_ASSERT_WORD_BOUNDARY 5
3048#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6
3049#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7
3050#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8
3051#define DUK_RETOK_ATOM_PERIOD 9
3052#define DUK_RETOK_ATOM_CHAR 10
3053#define DUK_RETOK_ATOM_DIGIT 11
3054#define DUK_RETOK_ATOM_NOT_DIGIT 12
3055#define DUK_RETOK_ATOM_WHITE 13
3056#define DUK_RETOK_ATOM_NOT_WHITE 14
3057#define DUK_RETOK_ATOM_WORD_CHAR 15
3058#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16
3059#define DUK_RETOK_ATOM_BACKREFERENCE 17
3060#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18
3061#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19
3062#define DUK_RETOK_ATOM_START_CHARCLASS 20
3063#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21
3064#define DUK_RETOK_ATOM_END_GROUP 22
3065
3066/* Constants for duk_lexer_ctx.buf. */
3067#define DUK_LEXER_TEMP_BUF_LIMIT 256
3068
3069/* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack.
3070 * Some fields (like num, str1, str2) are only valid for specific token types and may have
3071 * stale values otherwise.
3072 */
3073struct duk_token {
3074 duk_small_int_t t; /* token type (with reserved word identification) */
3075 duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
3076 duk_double_t num; /* numeric value of token */
3077 duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
3078 duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
3079 duk_size_t start_offset; /* start byte offset of token in lexer input */
3080 duk_int_t start_line; /* start line of token (first char) */
3081 duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */
3082 duk_bool_t lineterm; /* token was preceded by a lineterm */
3083 duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */
3084};
3085
3086#define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL)
3087
3088/* A regexp token value. */
3089struct duk_re_token {
3090 duk_small_int_t t; /* token type */
3091 duk_small_int_t greedy;
3092 duk_uint_fast32_t num; /* numeric value (character, count) */
3093 duk_uint_fast32_t qmin;
3094 duk_uint_fast32_t qmax;
3095};
3096
3097/* A structure for 'snapshotting' a point for rewinding */
3098struct duk_lexer_point {
3099 duk_size_t offset;
3100 duk_int_t line;
3101};
3102
3103/* Lexer codepoint with additional info like offset/line number */
3104struct duk_lexer_codepoint {
3105 duk_codepoint_t codepoint;
3106 duk_size_t offset;
3107 duk_int_t line;
3108};
3109
3110/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */
3111struct duk_lexer_ctx {
3112#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
3113 duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */
3114 duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE];
3115#else
3116 duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */
3117#endif
3118
3119 duk_hthread *thr; /* thread; minimizes argument passing */
3120
3121 const duk_uint8_t *input; /* input string (may be a user pointer) */
3122 duk_size_t input_length; /* input byte length */
3123 duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */
3124 duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */
3125
3126 duk_idx_t slot1_idx; /* valstack slot for 1st token value */
3127 duk_idx_t slot2_idx; /* valstack slot for 2nd token value */
3128 duk_idx_t buf_idx; /* valstack slot for temp buffer */
3129 duk_hbuffer_dynamic *buf; /* temp accumulation buffer */
3130 duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */
3131
3132 duk_int_t token_count; /* number of tokens parsed */
3133 duk_int_t token_limit; /* maximum token count before error (sanity backstop) */
3134};
3135
3136/*
3137 * Prototypes
3138 */
3139
3140DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
3141
3142DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
3143
3144DUK_INTERNAL_DECL
3145void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
3146 duk_token *out_token,
3147 duk_bool_t strict_mode,
3148 duk_bool_t regexp_mode);
3149#ifdef DUK_USE_REGEXP_SUPPORT
3150DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
3151DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
3152#endif /* DUK_USE_REGEXP_SUPPORT */
3153
3154#endif /* DUK_LEXER_H_INCLUDED */
3155#line 1 "duk_js_compiler.h"
3156/*
3157 * Ecmascript compiler.
3158 */
3159
3160#ifndef DUK_JS_COMPILER_H_INCLUDED
3161#define DUK_JS_COMPILER_H_INCLUDED
3162
3163/* ecmascript compiler limits */
3164#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */
3165
3166/* maximum loopcount for peephole optimization */
3167#define DUK_COMPILER_PEEPHOLE_MAXITER 3
3168
3169/* maximum bytecode length in instructions */
3170#define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */
3171
3172/*
3173 * Compiler intermediate values
3174 *
3175 * Intermediate values describe either plain values (e.g. strings or
3176 * numbers) or binary operations which have not yet been coerced into
3177 * either a left-hand-side or right-hand-side role (e.g. object property).
3178 */
3179
3180#define DUK_IVAL_NONE 0 /* no value */
3181#define DUK_IVAL_PLAIN 1 /* register, constant, or value */
3182#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
3183#define DUK_IVAL_ARITH_EXTRAOP 3 /* binary arithmetic using extraops; DUK_EXTRAOP_INSTOF etc */
3184#define DUK_IVAL_PROP 4 /* property access */
3185#define DUK_IVAL_VAR 5 /* variable access */
3186
3187#define DUK_ISPEC_NONE 0 /* no value */
3188#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */
3189#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */
3190
3191/* bit mask which indicates that a regconst is a constant instead of a register */
3192#define DUK_JS_CONST_MARKER 0x80000000UL
3193
3194/* type to represent a reg/const reference during compilation */
3195typedef duk_uint32_t duk_regconst_t;
3196
3197/* type to represent a straight register reference, with <0 indicating none */
3198typedef duk_int32_t duk_reg_t;
3199
3200typedef struct {
3201 duk_small_uint_t t; /* DUK_ISPEC_XXX */
3202 duk_regconst_t regconst;
3203 duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */
3204} duk_ispec;
3205
3206typedef struct {
3207 /*
3208 * PLAIN: x1
3209 * ARITH: x1 <op> x2
3210 * PROP: x1.x2
3211 * VAR: x1 (name)
3212 */
3213
3214 /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
3215 duk_small_uint_t t; /* DUK_IVAL_XXX */
3216 duk_small_uint_t op; /* bytecode opcode (or extraop) for binary ops */
3217 duk_ispec x1;
3218 duk_ispec x2;
3219} duk_ivalue;
3220
3221/*
3222 * Bytecode instruction representation during compilation
3223 *
3224 * Contains the actual instruction and (optionally) debug info.
3225 */
3226
3227struct duk_compiler_instr {
3228 duk_instr_t ins;
3229#if defined(DUK_USE_PC2LINE)
3230 duk_uint32_t line;
3231#endif
3232};
3233
3234/*
3235 * Compiler state
3236 */
3237
3238#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0)
3239#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1)
3240
3241#define DUK_DECL_TYPE_VAR 0
3242#define DUK_DECL_TYPE_FUNC 1
3243
3244/* XXX: optimize to 16 bytes */
3245typedef struct {
3246 duk_small_uint_t flags;
3247 duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */
3248 duk_hstring *h_label; /* borrowed label name */
3249 duk_int_t catch_depth; /* catch depth at point of definition */
3250 duk_int_t pc_label; /* pc of label statement:
3251 * pc+1: break jump site
3252 * pc+2: continue jump site
3253 */
3254
3255 /* Fast jumps (which avoid longjmp) jump directly to the jump sites
3256 * which are always known even while the iteration/switch statement
3257 * is still being parsed. A final peephole pass "straightens out"
3258 * the jumps.
3259 */
3260} duk_labelinfo;
3261
3262/* Compiling state of one function, eventually converted to duk_hcompiledfunction */
3263struct duk_compiler_func {
3264 /* These pointers are at the start of the struct so that they pack
3265 * nicely. Mixing pointers and integer values is bad on some
3266 * platforms (e.g. if int is 32 bits and pointers are 64 bits).
3267 */
3268
3269 duk_bufwriter_ctx bw_code; /* bufwriter for code */
3270
3271 duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */
3272 /* h_code: held in bw_code */
3273 duk_hobject *h_consts; /* array */
3274 duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2]
3275 * offset/line points to closing brace to allow skipping on pass 2
3276 */
3277 duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ]
3278 * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars)
3279 * record function and variable declarations in pass 1
3280 */
3281 duk_hobject *h_labelnames; /* array of active label names */
3282 duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */
3283 duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */
3284 duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
3285
3286 /* value stack indices for tracking objects */
3287 /* code_idx: not needed */
3288 duk_idx_t consts_idx;
3289 duk_idx_t funcs_idx;
3290 duk_idx_t decls_idx;
3291 duk_idx_t labelnames_idx;
3292 duk_idx_t labelinfos_idx;
3293 duk_idx_t argnames_idx;
3294 duk_idx_t varmap_idx;
3295
3296 /* temp reg handling */
3297 duk_reg_t temp_first; /* first register that is a temporary (below: variables) */
3298 duk_reg_t temp_next; /* next temporary register to allocate */
3299 duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
3300
3301 /* shuffle registers if large number of regs/consts */
3302 duk_reg_t shuffle1;
3303 duk_reg_t shuffle2;
3304 duk_reg_t shuffle3;
3305
3306 /* stats for current expression being parsed */
3307 duk_int_t nud_count;
3308 duk_int_t led_count;
3309 duk_int_t paren_level; /* parenthesis count, 0 = top level */
3310 duk_bool_t expr_lhs; /* expression is left-hand-side compatible */
3311 duk_bool_t allow_in; /* current paren level allows 'in' token */
3312
3313 /* misc */
3314 duk_int_t stmt_next; /* statement id allocation (running counter) */
3315 duk_int_t label_next; /* label id allocation (running counter) */
3316 duk_int_t catch_depth; /* catch stack depth */
3317 duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
3318 duk_int_t fnum_next; /* inner function numbering */
3319 duk_int_t num_formals; /* number of formal arguments */
3320 duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
3321#if defined(DUK_USE_DEBUGGER_SUPPORT)
3322 duk_int_t min_line; /* XXX: typing (duk_hcompiledfunction has duk_uint32_t) */
3323 duk_int_t max_line;
3324#endif
3325
3326 /* status booleans */
3327 duk_bool_t is_function; /* is an actual function (not global/eval code) */
3328 duk_bool_t is_eval; /* is eval code */
3329 duk_bool_t is_global; /* is global code */
3330 duk_bool_t is_setget; /* is a setter/getter */
3331 duk_bool_t is_decl; /* is a function declaration (as opposed to function expression) */
3332 duk_bool_t is_strict; /* function is strict */
3333 duk_bool_t is_notail; /* function must not be tail called */
3334 duk_bool_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
3335 duk_bool_t in_scanning; /* parsing in "scanning" phase (first pass) */
3336 duk_bool_t may_direct_eval; /* function may call direct eval */
3337 duk_bool_t id_access_arguments; /* function refers to 'arguments' identifier */
3338 duk_bool_t id_access_slow; /* function makes one or more slow path accesses */
3339 duk_bool_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
3340 duk_bool_t needs_shuffle; /* function needs shuffle registers */
3341 duk_bool_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
3342};
3343
3344struct duk_compiler_ctx {
3345 duk_hthread *thr;
3346
3347 /* filename being compiled (ends up in functions' '_filename' property) */
3348 duk_hstring *h_filename; /* borrowed reference */
3349
3350 /* lexing (tokenization) state (contains two valstack slot indices) */
3351 duk_lexer_ctx lex;
3352
3353 /* current and previous token for parsing */
3354 duk_token prev_token;
3355 duk_token curr_token;
3356 duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */
3357 duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */
3358 duk_idx_t tok21_idx; /* prev_token slot1 */
3359 duk_idx_t tok22_idx; /* prev_token slot2 */
3360
3361 /* recursion limit */
3362 duk_int_t recursion_depth;
3363 duk_int_t recursion_limit;
3364
3365 /* code emission temporary */
3366 duk_int_t emit_jumpslot_pc;
3367
3368 /* current function being compiled (embedded instead of pointer for more compact access) */
3369 duk_compiler_func curr_func;
3370};
3371
3372/*
3373 * Prototypes
3374 */
3375
3376#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */
3377#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */
3378#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */
3379
3380DUK_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);
3381
3382#endif /* DUK_JS_COMPILER_H_INCLUDED */
3383#line 1 "duk_regexp.h"
3384/*
3385 * Regular expression structs, constants, and bytecode defines.
3386 */
3387
3388#ifndef DUK_REGEXP_H_INCLUDED
3389#define DUK_REGEXP_H_INCLUDED
3390
3391/* maximum bytecode copies for {n,m} quantifiers */
3392#define DUK_RE_MAX_ATOM_COPIES 1000
3393
3394/* regexp compilation limits */
3395#define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */
3396
3397/* regexp execution limits */
3398#define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */
3399
3400/* regexp opcodes */
3401#define DUK_REOP_MATCH 1
3402#define DUK_REOP_CHAR 2
3403#define DUK_REOP_PERIOD 3
3404#define DUK_REOP_RANGES 4
3405#define DUK_REOP_INVRANGES 5
3406#define DUK_REOP_JUMP 6
3407#define DUK_REOP_SPLIT1 7
3408#define DUK_REOP_SPLIT2 8
3409#define DUK_REOP_SQMINIMAL 9
3410#define DUK_REOP_SQGREEDY 10
3411#define DUK_REOP_SAVE 11
3412#define DUK_REOP_WIPERANGE 12
3413#define DUK_REOP_LOOKPOS 13
3414#define DUK_REOP_LOOKNEG 14
3415#define DUK_REOP_BACKREFERENCE 15
3416#define DUK_REOP_ASSERT_START 16
3417#define DUK_REOP_ASSERT_END 17
3418#define DUK_REOP_ASSERT_WORD_BOUNDARY 18
3419#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
3420
3421/* flags */
3422#define DUK_RE_FLAG_GLOBAL (1 << 0)
3423#define DUK_RE_FLAG_IGNORE_CASE (1 << 1)
3424#define DUK_RE_FLAG_MULTILINE (1 << 2)
3425
3426struct duk_re_matcher_ctx {
3427 duk_hthread *thr;
3428
3429 duk_uint32_t re_flags;
3430 const duk_uint8_t *input;
3431 const duk_uint8_t *input_end;
3432 const duk_uint8_t *bytecode;
3433 const duk_uint8_t *bytecode_end;
3434 const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */
3435 duk_uint32_t nsaved;
3436 duk_uint32_t recursion_depth;
3437 duk_uint32_t recursion_limit;
3438 duk_uint32_t steps_count;
3439 duk_uint32_t steps_limit;
3440};
3441
3442struct duk_re_compiler_ctx {
3443 duk_hthread *thr;
3444
3445 duk_uint32_t re_flags;
3446 duk_lexer_ctx lex;
3447 duk_re_token curr_token;
3448 duk_bufwriter_ctx bw;
3449 duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */
3450 duk_uint32_t highest_backref;
3451 duk_uint32_t recursion_depth;
3452 duk_uint32_t recursion_limit;
3453 duk_uint32_t nranges; /* internal temporary value, used for char classes */
3454};
3455
3456/*
3457 * Prototypes
3458 */
3459
3460DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
3461DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
3462DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
3463DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */
3464
3465#endif /* DUK_REGEXP_H_INCLUDED */
3466#line 1 "duk_heaphdr.h"
3467/*
3468 * Heap header definition and assorted macros, including ref counting.
3469 * Access all fields through the accessor macros.
3470 */
3471
3472#ifndef DUK_HEAPHDR_H_INCLUDED
3473#define DUK_HEAPHDR_H_INCLUDED
3474
3475/*
3476 * Common heap header
3477 *
3478 * All heap objects share the same flags and refcount fields. Objects other
3479 * than strings also need to have a single or double linked list pointers
3480 * for insertion into the "heap allocated" list. Strings are held in the
3481 * heap-wide string table so they don't need link pointers.
3482 *
3483 * Technically, 'h_refcount' must be wide enough to guarantee that it cannot
3484 * wrap (otherwise objects might be freed incorrectly after wrapping). This
3485 * means essentially that the refcount field must be as wide as data pointers.
3486 * On 64-bit platforms this means that the refcount needs to be 64 bits even
3487 * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on
3488 * this might be reasonable in the future.
3489 *
3490 * Heap header size on 32-bit platforms: 8 bytes without reference counting,
3491 * 16 bytes with reference counting.
3492 */
3493
3494struct duk_heaphdr {
3495 duk_uint32_t h_flags;
3496
3497#if defined(DUK_USE_REFERENCE_COUNTING)
3498#if defined(DUK_USE_REFCOUNT16)
3499 duk_uint16_t h_refcount16;
3500#else
3501 duk_size_t h_refcount;
3502#endif
3503#endif
3504
3505#if defined(DUK_USE_HEAPPTR16)
3506 duk_uint16_t h_next16;
3507#else
3508 duk_heaphdr *h_next;
3509#endif
3510
3511#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3512 /* refcounting requires direct heap frees, which in turn requires a dual linked heap */
3513#if defined(DUK_USE_HEAPPTR16)
3514 duk_uint16_t h_prev16;
3515#else
3516 duk_heaphdr *h_prev;
3517#endif
3518#endif
3519
3520 /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
3521 * struct won't align nicely to 4 bytes. This 16-bit extra field
3522 * is added to make the alignment clean; the field can be used by
3523 * heap objects when 16-bit packing is used. This field is now
3524 * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
3525 * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
3526 * this only matter to low memory environments anyway.
3527 */
3528#if defined(DUK_USE_HEAPPTR16)
3529 duk_uint16_t h_extra16;
3530#endif
3531};
3532
3533struct duk_heaphdr_string {
3534 /* 16 bits would be enough for shared heaphdr flags and duk_hstring
3535 * flags. The initial parts of duk_heaphdr_string and duk_heaphdr
3536 * must match so changing the flags field size here would be quite
3537 * awkward. However, to minimize struct size, we can pack at least
3538 * 16 bits of duk_hstring data into the flags field.
3539 */
3540 duk_uint32_t h_flags;
3541
3542#if defined(DUK_USE_REFERENCE_COUNTING)
3543#if defined(DUK_USE_REFCOUNT16)
3544 duk_uint16_t h_refcount16;
3545 duk_uint16_t h_strextra16; /* round out to 8 bytes */
3546#else
3547 duk_size_t h_refcount;
3548#endif
3549#else
3550 duk_uint16_t h_strextra16;
3551#endif
3552};
3553
3554#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
3555#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
3556
3557 /* 2 bits for heap type */
3558#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */
3559#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */
3560
3561#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
3562#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n))
3563#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
3564#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
3565
3566#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */
3567#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */
3568#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */
3569#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
3570#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
3571
3572#define DUK_HTYPE_MIN 1
3573#define DUK_HTYPE_STRING 1
3574#define DUK_HTYPE_OBJECT 2
3575#define DUK_HTYPE_BUFFER 3
3576#define DUK_HTYPE_MAX 3
3577
3578#if defined(DUK_USE_HEAPPTR16)
3579#define DUK_HEAPHDR_GET_NEXT(heap,h) \
3580 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
3581#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
3582 (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
3583 } while (0)
3584#else
3585#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next)
3586#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
3587 (h)->h_next = (val); \
3588 } while (0)
3589#endif
3590
3591#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3592#if defined(DUK_USE_HEAPPTR16)
3593#define DUK_HEAPHDR_GET_PREV(heap,h) \
3594 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
3595#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
3596 (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
3597 } while (0)
3598#else
3599#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev)
3600#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
3601 (h)->h_prev = (val); \
3602 } while (0)
3603#endif
3604#endif
3605
3606#if defined(DUK_USE_REFERENCE_COUNTING)
3607#if defined(DUK_USE_REFCOUNT16)
3608#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16)
3609#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
3610 (h)->h_refcount16 = (val); \
3611 } while (0)
3612#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */
3613#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */
3614#else
3615#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
3616#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
3617 (h)->h_refcount = (val); \
3618 } while (0)
3619#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
3620#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
3621#endif
3622#else
3623/* refcount macros not defined without refcounting, caller must #ifdef now */
3624#endif /* DUK_USE_REFERENCE_COUNTING */
3625
3626/*
3627 * Note: type is treated as a field separate from flags, so some masking is
3628 * involved in the macros below.
3629 */
3630
3631#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
3632
3633#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
3634#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
3635 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
3636 } while (0)
3637
3638#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
3639#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
3640 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
3641 } while (0)
3642
3643#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
3644 DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \
3645 DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
3646 )
3647
3648#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \
3649 (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
3650 ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
3651 } while (0)
3652
3653#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \
3654 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
3655 (h)->h_flags |= (bits); \
3656 } while (0)
3657
3658#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \
3659 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
3660 (h)->h_flags &= ~((bits)); \
3661 } while (0)
3662
3663#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0)
3664
3665#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3666#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3667#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3668
3669#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3670#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3671#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3672
3673#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3674#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3675#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3676
3677#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3678#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3679#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3680
3681#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3682#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3683#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3684
3685/* get or set a range of flags; m=first bit number, n=number of bits */
3686#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
3687
3688#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \
3689 (h)->h_flags = \
3690 ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
3691 | ((v) << (m)); \
3692 } while (0)
3693
3694/* init pointer fields to null */
3695#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3696#define DUK_HEAPHDR_INIT_NULLS(h) do { \
3697 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
3698 DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
3699 } while (0)
3700#else
3701#define DUK_HEAPHDR_INIT_NULLS(h) do { \
3702 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
3703 } while (0)
3704#endif
3705
3706#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */
3707
3708/*
3709 * Assert helpers
3710 */
3711
3712/* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
3713 * h->prev->next should point back to h.
3714 */
3715#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS)
3716#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \
3717 if ((h) != NULL) { \
3718 duk_heaphdr *h__prev, *h__next; \
3719 h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \
3720 h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \
3721 DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \
3722 DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \
3723 } \
3724 } while (0)
3725#else
3726#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
3727#endif
3728
3729/*
3730 * Reference counting helper macros. The macros take a thread argument
3731 * and must thus always be executed in a specific thread context. The
3732 * thread argument is needed for features like finalization. Currently
3733 * it is not required for INCREF, but it is included just in case.
3734 *
3735 * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
3736 * defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef
3737 * around them.
3738 */
3739
3740#if defined(DUK_USE_REFERENCE_COUNTING)
3741
3742#if defined(DUK_USE_ROM_OBJECTS)
3743/* With ROM objects "needs refcount update" is true when the value is
3744 * heap allocated and is not a ROM object.
3745 */
3746/* XXX: double evaluation for 'tv' argument. */
3747#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \
3748 (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv))))
3749#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h)))
3750#else /* DUK_USE_ROM_OBJECTS */
3751/* Without ROM objects "needs refcount update" == is heap allocated. */
3752#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv))
3753#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1
3754#endif /* DUK_USE_ROM_OBJECTS */
3755
3756/* Fast variants, inline refcount operations except for refzero handling.
3757 * Can be used explicitly when speed is always more important than size.
3758 * For a good compiler and a single file build, these are basically the
3759 * same as a forced inline.
3760 */
3761#define DUK_TVAL_INCREF_FAST(thr,tv) do { \
3762 duk_tval *duk__tv = (tv); \
3763 DUK_ASSERT(duk__tv != NULL); \
3764 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
3765 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
3766 DUK_ASSERT(duk__h != NULL); \
3767 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
3768 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
3769 } \
3770 } while (0)
3771#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
3772 duk_tval *duk__tv = (tv); \
3773 DUK_ASSERT(duk__tv != NULL); \
3774 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
3775 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
3776 DUK_ASSERT(duk__h != NULL); \
3777 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
3778 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
3779 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
3780 duk_heaphdr_refzero((thr), duk__h); \
3781 } \
3782 } \
3783 } while (0)
3784#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
3785 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
3786 DUK_ASSERT(duk__h != NULL); \
3787 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
3788 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
3789 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
3790 } \
3791 } while (0)
3792#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \
3793 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
3794 DUK_ASSERT(duk__h != NULL); \
3795 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
3796 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
3797 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
3798 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
3799 duk_heaphdr_refzero((thr), duk__h); \
3800 } \
3801 } \
3802 } while (0)
3803
3804/* Slow variants, call to a helper to reduce code size.
3805 * Can be used explicitly when size is always more important than speed.
3806 */
3807#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \
3808 duk_tval_incref((tv)); \
3809 } while (0)
3810#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \
3811 duk_tval_decref((thr), (tv)); \
3812 } while (0)
3813#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \
3814 duk_heaphdr_incref((duk_heaphdr *) (h)); \
3815 } while (0)
3816#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \
3817 duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \
3818 } while (0)
3819
3820/* Default variants. Selection depends on speed/size preference.
3821 * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
3822 * is about +1kB for _FAST variants.
3823 */
3824#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
3825#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
3826#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
3827#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
3828#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h))
3829#else
3830#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
3831#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
3832#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
3833#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
3834#endif
3835
3836/* Casting convenience. */
3837#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
3838#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
3839#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
3840#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
3841#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
3842#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
3843#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3844#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3845#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3846#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3847#define DUK_HBUFFEROBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3848#define DUK_HBUFFEROBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3849#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3850#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3851
3852/* Convenience for some situations; the above macros don't allow NULLs
3853 * for performance reasons.
3854 */
3855#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
3856 if ((h) != NULL) { \
3857 DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
3858 } \
3859 } while (0)
3860#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
3861 if ((h) != NULL) { \
3862 DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
3863 } \
3864 } while (0)
3865
3866/*
3867 * Macros to set a duk_tval and update refcount of the target (decref the
3868 * old value and incref the new value if necessary). This is both performance
3869 * and footprint critical; any changes made should be measured for size/speed.
3870 */
3871
3872#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
3873 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3874 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3875 DUK_TVAL_SET_UNDEFINED(tv__dst); \
3876 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3877 } while (0)
3878
3879#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
3880 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3881 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3882 DUK_TVAL_SET_UNUSED(tv__dst); \
3883 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3884 } while (0)
3885
3886#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
3887 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3888 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3889 DUK_TVAL_SET_NULL(tv__dst); \
3890 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3891 } while (0)
3892
3893#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3894 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3895 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3896 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
3897 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3898 } while (0)
3899
3900#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3901 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3902 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3903 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
3904 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3905 } while (0)
3906#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3907 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3908 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3909 DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
3910 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3911 } while (0)
3912#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3913 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3914 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3915 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
3916 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3917 } while (0)
3918#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
3919 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3920 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3921 DUK_TVAL_SET_NAN(tv__dst); \
3922 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3923 } while (0)
3924#if defined(DUK_USE_FASTINT)
3925#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3926 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3927 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3928 DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
3929 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3930 } while (0)
3931#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3932 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3933 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3934 DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
3935 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3936 } while (0)
3937#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3938 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3939 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3940 DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
3941 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3942 } while (0)
3943#else
3944#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
3945 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
3946#endif /* DUK_USE_FASTINT */
3947
3948#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) 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_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
3952 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3953 } while (0)
3954
3955#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3956 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3957 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3958 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
3959 DUK_HSTRING_INCREF((thr), (newval)); \
3960 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3961 } while (0)
3962
3963#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3964 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3965 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3966 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
3967 DUK_HOBJECT_INCREF((thr), (newval)); \
3968 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3969 } while (0)
3970
3971#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3972 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3973 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3974 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
3975 DUK_HBUFFER_INCREF((thr), (newval)); \
3976 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3977 } while (0)
3978
3979#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3980 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3981 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3982 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
3983 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3984 } while (0)
3985
3986/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
3987 * etc, so it's very important for performance. Measure when changing.
3988 *
3989 * NOTE: the source and destination duk_tval pointers may be the same, and
3990 * the macros MUST deal with that correctly.
3991 */
3992
3993/* Original idiom used, minimal code size. */
3994#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
3995 duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
3996 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
3997 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3998 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
3999 DUK_TVAL_INCREF((thr), tv__src); \
4000 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4001 } while (0)
4002
4003/* Faster alternative: avoid making a temporary copy of tvptr_dst and use
4004 * fast incref/decref macros.
4005 */
4006#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
4007 duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
4008 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
4009 DUK_TVAL_INCREF_FAST((thr), tv__src); \
4010 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \
4011 h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
4012 DUK_ASSERT(h__obj != NULL); \
4013 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4014 DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
4015 } else { \
4016 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4017 } \
4018 } while (0)
4019
4020/* XXX: no optimized variants yet */
4021#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
4022#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
4023#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
4024#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
4025#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
4026#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
4027#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
4028#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
4029#if defined(DUK_USE_FASTINT)
4030#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
4031#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
4032#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
4033#else
4034#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
4035#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4036#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4037#endif /* DUK_USE_FASTINT */
4038#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
4039#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
4040#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
4041#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
4042#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
4043
4044#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
4045/* Optimized for speed. */
4046#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1
4047#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1
4048#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4049#else
4050/* Optimized for size. */
4051#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
4052#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
4053#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4054#endif
4055
4056#else /* DUK_USE_REFERENCE_COUNTING */
4057
4058#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0
4059#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0
4060
4061#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
4062#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
4063#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
4064#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
4065#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
4066#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
4067#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
4068#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
4069#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
4070#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
4071#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
4072#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
4073#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
4074#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
4075#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
4076#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
4077#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
4078#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
4079#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
4080#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
4081#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
4082#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
4083#define DUK_HBUFFEROBJECT_INCREF(thr,h) do {} while (0) /* nop */
4084#define DUK_HBUFFEROBJECT_DECREF(thr,h) do {} while (0) /* nop */
4085#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
4086#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
4087#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4088#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4089
4090#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
4091 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4092 DUK_TVAL_SET_UNDEFINED(tv__dst); \
4093 DUK_UNREF((thr)); \
4094 } while (0)
4095
4096#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
4097 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4098 DUK_TVAL_SET_UNUSED(tv__dst); \
4099 DUK_UNREF((thr)); \
4100 } while (0)
4101
4102#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
4103 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4104 DUK_TVAL_SET_NULL(tv__dst); \
4105 DUK_UNREF((thr)); \
4106 } while (0)
4107
4108#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4109 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4110 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
4111 DUK_UNREF((thr)); \
4112 } while (0)
4113
4114#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4115 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4116 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
4117 DUK_UNREF((thr)); \
4118 } while (0)
4119#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4120 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4121 DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
4122 DUK_UNREF((thr)); \
4123 } while (0)
4124#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4125 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4126 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
4127 DUK_UNREF((thr)); \
4128 } while (0)
4129#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
4130 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4131 DUK_TVAL_SET_NAN(tv__dst); \
4132 DUK_UNREF((thr)); \
4133 } while (0)
4134#if defined(DUK_USE_FASTINT)
4135#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4136 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4137 DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
4138 DUK_UNREF((thr)); \
4139 } while (0)
4140#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4141 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4142 DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
4143 DUK_UNREF((thr)); \
4144 } while (0)
4145#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4146 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4147 DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
4148 DUK_UNREF((thr)); \
4149 } while (0)
4150#else
4151#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
4152 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
4153#endif /* DUK_USE_FASTINT */
4154
4155#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
4156 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4157 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
4158 DUK_UNREF((thr)); \
4159 } while (0)
4160
4161#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4162 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4163 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
4164 DUK_UNREF((thr)); \
4165 } while (0)
4166
4167#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4168 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4169 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
4170 DUK_UNREF((thr)); \
4171 } while (0)
4172
4173#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4174 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4175 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
4176 DUK_UNREF((thr)); \
4177 } while (0)
4178
4179#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4180 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4181 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
4182 DUK_UNREF((thr)); \
4183 } while (0)
4184
4185#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
4186 duk_tval *tv__dst, *tv__src; \
4187 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
4188 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4189 DUK_UNREF((thr)); \
4190 } while (0)
4191
4192#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
4193#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
4194#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
4195#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
4196#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
4197#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
4198#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
4199#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
4200#if defined(DUK_USE_FASTINT)
4201#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
4202#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
4203#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
4204#else
4205#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
4206#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4207#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4208#endif /* DUK_USE_FASTINT */
4209#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
4210#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
4211#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
4212#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
4213#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
4214
4215#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
4216#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
4217#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4218
4219#endif /* DUK_USE_REFERENCE_COUNTING */
4220
4221#endif /* DUK_HEAPHDR_H_INCLUDED */
4222#line 1 "duk_api_internal.h"
4223/*
4224 * Internal API calls which have (stack and other) semantics similar
4225 * to the public API.
4226 */
4227
4228#ifndef DUK_API_INTERNAL_H_INCLUDED
4229#define DUK_API_INTERNAL_H_INCLUDED
4230
4231/* duk_push_sprintf constants */
4232#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
4233#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
4234
4235/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
4236 * blamed as source of error for error fileName / lineNumber.
4237 */
4238#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
4239
4240/* Valstack resize flags */
4241#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0)
4242#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1)
4243#define DUK_VSRESIZE_FLAG_THROW (1 << 2)
4244
4245/* Current convention is to use duk_size_t for value stack sizes and global indices,
4246 * and duk_idx_t for local frame indices.
4247 */
4248DUK_INTERNAL_DECL
4249duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
4250 duk_size_t min_new_size,
4251 duk_small_uint_t flags);
4252
4253#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
4254DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index);
4255#endif
4256
4257DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index);
4258DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index);
4259DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
4260
4261/* Push the current 'this' binding; throw TypeError if binding is not object
4262 * coercible (CheckObjectCoercible).
4263 */
4264DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx);
4265
4266/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
4267DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);
4268
4269/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
4270DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);
4271
4272/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
4273 * make sure there's an active callstack entry. Note that the returned pointer
4274 * is unstable with regards to side effects.
4275 */
4276DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
4277
4278/* XXX: add fastint support? */
4279#define duk_push_u64(ctx,val) \
4280 duk_push_number((ctx), (duk_double_t) (val))
4281#define duk_push_i64(ctx,val) \
4282 duk_push_number((ctx), (duk_double_t) (val))
4283
4284/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
4285#define duk_push_u32(ctx,val) \
4286 duk_push_uint((ctx), (duk_uint_t) (val))
4287#define duk_push_i32(ctx,val) \
4288 duk_push_int((ctx), (duk_int_t) (val))
4289
4290/* sometimes stack and array indices need to go on the stack */
4291#define duk_push_idx(ctx,val) \
4292 duk_push_int((ctx), (duk_int_t) (val))
4293#define duk_push_uarridx(ctx,val) \
4294 duk_push_uint((ctx), (duk_uint_t) (val))
4295#define duk_push_size_t(ctx,val) \
4296 duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
4297
4298DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index);
4299DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index);
4300DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index);
4301DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index);
4302DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index);
4303DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index);
4304
4305DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
4306
4307#if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */
4308DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
4309#endif
4310DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
4311
4312#if 0 /*unused*/
4313DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index);
4314#endif
4315
4316DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index);
4317#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
4318DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index);
4319#endif
4320DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx);
4321#if !defined(DUK_USE_PARANOID_ERRORS)
4322DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h);
4323#endif
4324
4325DUK_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 */
4326DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
4327DUK_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);
4328#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
4329DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index);
4330#endif
4331
4332DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index);
4333DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index);
4334DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index);
4335DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index);
4336DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index);
4337DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index);
4338
4339DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
4340
4341DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
4342DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
4343
4344DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h);
4345DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx);
4346DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h);
4347DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
4348#define duk_push_hthread(ctx,h) \
4349 duk_push_hobject((ctx), (duk_hobject *) (h))
4350#define duk_push_hcompiledfunction(ctx,h) \
4351 duk_push_hobject((ctx), (duk_hobject *) (h))
4352#define duk_push_hnativefunction(ctx,h) \
4353 duk_push_hobject((ctx), (duk_hobject *) (h))
4354DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx);
4355DUK_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);
4356DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
4357DUK_INTERNAL_DECL duk_idx_t duk_push_object_internal(duk_context *ctx);
4358DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx);
4359DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
4360DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
4361
4362DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz);
4363DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
4364DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
4365DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
4366
4367#if !defined(DUK_USE_PARANOID_ERRORS)
4368DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index);
4369DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
4370#endif
4371
4372DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */
4373DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */
4374DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
4375DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
4376
4377DUK_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); /* [] -> [] */
4378
4379DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags); /* [key val] -> [] */
4380DUK_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] -> [] */
4381DUK_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] -> [] */
4382DUK_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); /* [] -> [] */
4383DUK_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); /* [] -> [] */
4384
4385/* These are macros for now, but could be separate functions to reduce code
4386 * footprint (check call site count before refactoring).
4387 */
4388#define duk_xdef_prop_wec(ctx,obj_index) \
4389 duk_xdef_prop((ctx), (obj_index), DUK_PROPDESC_FLAGS_WEC)
4390#define duk_xdef_prop_index_wec(ctx,obj_index,arr_index) \
4391 duk_xdef_prop_index((ctx), (obj_index), (arr_index), DUK_PROPDESC_FLAGS_WEC)
4392#define duk_xdef_prop_stridx_wec(ctx,obj_index,stridx) \
4393 duk_xdef_prop_stridx((ctx), (obj_index), (stridx), DUK_PROPDESC_FLAGS_WEC)
4394
4395/* Set object 'length'. */
4396DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length);
4397
4398/* Raw internal valstack access macros: access is unsafe so call site
4399 * must have a guarantee that the index is valid. When that is the case,
4400 * using these macro results in faster and smaller code than duk_get_tval().
4401 * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
4402 */
4403#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
4404 (DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
4405#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
4406 (DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
4407#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
4408 (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
4409#define DUK_GET_TVAL_POSIDX(ctx,idx) \
4410 (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
4411#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
4412 (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
4413#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
4414 (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
4415
4416#endif /* DUK_API_INTERNAL_H_INCLUDED */
4417#line 1 "duk_hstring.h"
4418/*
4419 * Heap string representation.
4420 *
4421 * Strings are byte sequences ordinarily stored in extended UTF-8 format,
4422 * allowing values larger than the official UTF-8 range (used internally)
4423 * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format).
4424 * Strings may also be invalid UTF-8 altogether which is the case e.g. with
4425 * strings used as internal property names and raw buffers converted to
4426 * strings. In such cases the 'clen' field contains an inaccurate value.
4427 *
4428 * Ecmascript requires support for 32-bit long strings. However, since each
4429 * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only
4430 * support about 1.4G codepoint long strings in extreme cases. This is not
4431 * really a practical issue.
4432 */
4433
4434#ifndef DUK_HSTRING_H_INCLUDED
4435#define DUK_HSTRING_H_INCLUDED
4436
4437/* Impose a maximum string length for now. Restricted artificially to
4438 * ensure adding a heap header length won't overflow size_t. The limit
4439 * should be synchronized with DUK_HBUFFER_MAX_BYTELEN.
4440 *
4441 * E5.1 makes provisions to support strings longer than 4G characters.
4442 * This limit should be eliminated on 64-bit platforms (and increased
4443 * closer to maximum support on 32-bit platforms).
4444 */
4445
4446#if defined(DUK_USE_STRLEN16)
4447#define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL)
4448#else
4449#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL)
4450#endif
4451
4452/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings),
4453 * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
4454 * regexp bytecode is), and "contains non-BMP characters". These are not
4455 * needed right now.
4456 */
4457
4458#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
4459#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
4460#define DUK_HSTRING_FLAG_INTERNAL DUK_HEAPHDR_USER_FLAG(2) /* string is internal */
4461#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(3) /* string is a reserved word (non-strict) */
4462#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (strict) */
4463#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(5) /* string is 'eval' or 'arguments' */
4464#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(6) /* string data is external (duk_hstring_external) */
4465
4466#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
4467#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
4468#define DUK_HSTRING_HAS_INTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
4469#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
4470#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
4471#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
4472#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
4473
4474#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
4475#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
4476#define DUK_HSTRING_SET_INTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
4477#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
4478#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
4479#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
4480#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
4481
4482#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
4483#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
4484#define DUK_HSTRING_CLEAR_INTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
4485#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
4486#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
4487#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
4488#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
4489
4490#if 0 /* Slightly smaller code without explicit flag, but explicit flag
4491 * is very useful when 'clen' is dropped.
4492 */
4493#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
4494#endif
4495#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x))
4496#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0)
4497
4498#if defined(DUK_USE_STRHASH16)
4499#define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16)
4500#define DUK_HSTRING_SET_HASH(x,v) do { \
4501 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \
4502 } while (0)
4503#else
4504#define DUK_HSTRING_GET_HASH(x) ((x)->hash)
4505#define DUK_HSTRING_SET_HASH(x,v) do { \
4506 (x)->hash = (v); \
4507 } while (0)
4508#endif
4509
4510#if defined(DUK_USE_STRLEN16)
4511#define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16)
4512#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
4513 (x)->hdr.h_strextra16 = (v); \
4514 } while (0)
4515#if defined(DUK_USE_HSTRING_CLEN)
4516#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16)
4517#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
4518 (x)->clen16 = (v); \
4519 } while (0)
4520#else
4521#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
4522#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
4523 DUK_ASSERT(0); /* should never be called */ \
4524 } while (0)
4525#endif
4526#else
4527#define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen)
4528#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
4529 (x)->blen = (v); \
4530 } while (0)
4531#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen)
4532#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
4533 (x)->clen = (v); \
4534 } while (0)
4535#endif
4536
4537#if defined(DUK_USE_HSTRING_EXTDATA)
4538#define DUK_HSTRING_GET_EXTDATA(x) \
4539 ((x)->extdata)
4540#define DUK_HSTRING_GET_DATA(x) \
4541 (DUK_HSTRING_HAS_EXTDATA((x)) ? \
4542 DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1)))
4543#else
4544#define DUK_HSTRING_GET_DATA(x) \
4545 ((const duk_uint8_t *) ((x) + 1))
4546#endif
4547
4548#define DUK_HSTRING_GET_DATA_END(x) \
4549 (DUK_HSTRING_GET_DATA((x)) + (x)->blen)
4550
4551/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
4552#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
4553
4554/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
4555 * avoids helper call if string has no array index value.
4556 */
4557#define DUK_HSTRING_GET_ARRIDX_FAST(h) \
4558 (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
4559
4560/* slower but more compact variant */
4561#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \
4562 (duk_js_to_arrayindex_string_helper((h)))
4563
4564/*
4565 * Misc
4566 */
4567
4568struct duk_hstring {
4569 /* Smaller heaphdr than for other objects, because strings are held
4570 * in string intern table which requires no link pointers. Much of
4571 * the 32-bit flags field is unused by flags, so we can stuff a 16-bit
4572 * field in there.
4573 */
4574 duk_heaphdr_string hdr;
4575
4576 /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the
4577 * shared heap header. Good hashing needs more hash bits though.
4578 */
4579
4580 /* string hash */
4581#if defined(DUK_USE_STRHASH16)
4582 /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
4583#else
4584 duk_uint32_t hash;
4585#endif
4586
4587 /* length in bytes (not counting NUL term) */
4588#if defined(DUK_USE_STRLEN16)
4589 /* placed in duk_heaphdr_string */
4590#else
4591 duk_uint32_t blen;
4592#endif
4593
4594 /* length in codepoints (must be E5 compatible) */
4595#if defined(DUK_USE_STRLEN16)
4596#if defined(DUK_USE_HSTRING_CLEN)
4597 duk_uint16_t clen16;
4598#else
4599 /* computed live */
4600#endif
4601#else
4602 duk_uint32_t clen;
4603#endif
4604
4605 /*
4606 * String value of 'blen+1' bytes follows (+1 for NUL termination
4607 * convenience for C API). No alignment needs to be guaranteed
4608 * for strings, but fields above should guarantee alignment-by-4
4609 * (but not alignment-by-8).
4610 */
4611};
4612
4613/* The external string struct is defined even when the feature is inactive. */
4614struct duk_hstring_external {
4615 duk_hstring str;
4616
4617 /*
4618 * For an external string, the NUL-terminated string data is stored
4619 * externally. The user must guarantee that data behind this pointer
4620 * doesn't change while it's used.
4621 */
4622
4623 const duk_uint8_t *extdata;
4624};
4625
4626/*
4627 * Prototypes
4628 */
4629
4630DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos);
4631
4632#if !defined(DUK_USE_HSTRING_CLEN)
4633DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
4634#endif
4635
4636#endif /* DUK_HSTRING_H_INCLUDED */
4637#line 1 "duk_hobject.h"
4638/*
4639 * Heap object representation.
4640 *
4641 * Heap objects are used for Ecmascript objects, arrays, and functions,
4642 * but also for internal control like declarative and object environment
4643 * records. Compiled functions, native functions, and threads are also
4644 * objects but with an extended C struct.
4645 *
4646 * Objects provide the required Ecmascript semantics and exotic behaviors
4647 * especially for property access.
4648 *
4649 * Properties are stored in three conceptual parts:
4650 *
4651 * 1. A linear 'entry part' contains ordered key-value-attributes triples
4652 * and is the main method of string properties.
4653 *
4654 * 2. An optional linear 'array part' is used for array objects to store a
4655 * (dense) range of [0,N[ array indexed entries with default attributes
4656 * (writable, enumerable, configurable). If the array part would become
4657 * sparse or non-default attributes are required, the array part is
4658 * abandoned and moved to the 'entry part'.
4659 *
4660 * 3. An optional 'hash part' is used to optimize lookups of the entry
4661 * part; it is used only for objects with sufficiently many properties
4662 * and can be abandoned without loss of information.
4663 *
4664 * These three conceptual parts are stored in a single memory allocated area.
4665 * This minimizes memory allocation overhead but also means that all three
4666 * parts are resized together, and makes property access a bit complicated.
4667 */
4668
4669#ifndef DUK_HOBJECT_H_INCLUDED
4670#define DUK_HOBJECT_H_INCLUDED
4671
4672/* Object flag. There are currently 26 flag bits available. Make sure
4673 * this stays in sync with debugger object inspection code.
4674 */
4675#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
4676#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
4677#define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */
4678#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */
4679#define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */
4680#define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */
4681#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */
4682#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
4683#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
4684#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
4685#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */
4686#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
4687#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
4688#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */
4689#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
4690#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
4691#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
4692#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */
4693#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
4694
4695#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
4696#define DUK_HOBJECT_FLAG_CLASS_BITS 5
4697
4698#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \
4699 DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
4700#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \
4701 DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
4702
4703#define DUK_HOBJECT_GET_CLASS_MASK(h) \
4704 (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS))
4705
4706/* Macro for creating flag initializer from a class number.
4707 * Unsigned type cast is needed to avoid warnings about coercing
4708 * a signed integer to an unsigned one; the largest class values
4709 * have the highest bit (bit 31) set which causes this.
4710 */
4711#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
4712
4713/* E5 Section 8.6.2 + custom classes */
4714#define DUK_HOBJECT_CLASS_UNUSED 0
4715#define DUK_HOBJECT_CLASS_ARGUMENTS 1
4716#define DUK_HOBJECT_CLASS_ARRAY 2
4717#define DUK_HOBJECT_CLASS_BOOLEAN 3
4718#define DUK_HOBJECT_CLASS_DATE 4
4719#define DUK_HOBJECT_CLASS_ERROR 5
4720#define DUK_HOBJECT_CLASS_FUNCTION 6
4721#define DUK_HOBJECT_CLASS_JSON 7
4722#define DUK_HOBJECT_CLASS_MATH 8
4723#define DUK_HOBJECT_CLASS_NUMBER 9
4724#define DUK_HOBJECT_CLASS_OBJECT 10
4725#define DUK_HOBJECT_CLASS_REGEXP 11
4726#define DUK_HOBJECT_CLASS_STRING 12
4727#define DUK_HOBJECT_CLASS_GLOBAL 13
4728#define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */
4729#define DUK_HOBJECT_CLASS_DECENV 15 /* custom */
4730#define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */
4731#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
4732#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
4733#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */
4734#define DUK_HOBJECT_CLASS_DATAVIEW 20
4735#define DUK_HOBJECT_CLASS_INT8ARRAY 21
4736#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
4737#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23
4738#define DUK_HOBJECT_CLASS_INT16ARRAY 24
4739#define DUK_HOBJECT_CLASS_UINT16ARRAY 25
4740#define DUK_HOBJECT_CLASS_INT32ARRAY 26
4741#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
4742#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
4743#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
4744#define DUK_HOBJECT_CLASS_MAX 29
4745
4746/* class masks */
4747#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
4748#define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED)
4749#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
4750#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
4751#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
4752#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE)
4753#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR)
4754#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION)
4755#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON)
4756#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH)
4757#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER)
4758#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT)
4759#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
4760#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
4761#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
4762#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
4763#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
4764#define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER)
4765#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
4766#define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD)
4767#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
4768#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
4769#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
4770#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY)
4771#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY)
4772#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY)
4773#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY)
4774#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY)
4775#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY)
4776#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
4777#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
4778
4779#define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \
4780 (DUK_HOBJECT_CMASK_BUFFER | \
4781 DUK_HOBJECT_CMASK_ARRAYBUFFER | \
4782 DUK_HOBJECT_CMASK_DATAVIEW | \
4783 DUK_HOBJECT_CMASK_INT8ARRAY | \
4784 DUK_HOBJECT_CMASK_UINT8ARRAY | \
4785 DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \
4786 DUK_HOBJECT_CMASK_INT16ARRAY | \
4787 DUK_HOBJECT_CMASK_UINT16ARRAY | \
4788 DUK_HOBJECT_CMASK_INT32ARRAY | \
4789 DUK_HOBJECT_CMASK_UINT32ARRAY | \
4790 DUK_HOBJECT_CMASK_FLOAT32ARRAY | \
4791 DUK_HOBJECT_CMASK_FLOAT64ARRAY)
4792
4793#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
4794#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
4795#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
4796#define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY)
4797#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4798#define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4799#define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4800#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4801
4802#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
4803 DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
4804 DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4805
4806#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
4807 DUK_HOBJECT_FLAG_BOUND | \
4808 DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
4809 DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4810
4811#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
4812 DUK_HOBJECT_FLAG_BOUND | \
4813 DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
4814 DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4815
4816/* object has any exotic behavior(s) */
4817#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
4818 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
4819 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
4820 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
4821 DUK_HOBJECT_FLAG_BUFFEROBJECT | \
4822 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4823
4824#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
4825
4826#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
4827#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
4828#define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
4829#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4830#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4831#define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4832#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4833#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
4834#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
4835#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
4836#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
4837#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
4838#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
4839#define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
4840#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
4841#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
4842#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
4843#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
4844#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4845
4846#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
4847#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
4848#define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
4849#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4850#define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4851#define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4852#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4853#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
4854#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
4855#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
4856#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
4857#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
4858#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
4859#define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
4860#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
4861#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
4862#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
4863#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
4864#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4865
4866#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
4867#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
4868#define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
4869#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4870#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4871#define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4872#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4873#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
4874#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
4875#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
4876#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
4877#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
4878#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
4879#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
4880#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
4881#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
4882#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
4883#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
4884#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4885
4886/* flags used for property attributes in duk_propdesc and packed flags */
4887#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
4888#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
4889#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
4890#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
4891#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
4892 * (used by e.g. buffer virtual properties)
4893 */
4894#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
4895 DUK_PROPDESC_FLAG_ENUMERABLE | \
4896 DUK_PROPDESC_FLAG_CONFIGURABLE | \
4897 DUK_PROPDESC_FLAG_ACCESSOR)
4898
4899/* additional flags which are passed in the same flags argument as property
4900 * flags but are not stored in object properties.
4901 */
4902#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */
4903
4904/* convenience */
4905#define DUK_PROPDESC_FLAGS_NONE 0
4906#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
4907#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
4908#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE)
4909#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
4910#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
4911#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
4912#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \
4913 DUK_PROPDESC_FLAG_ENUMERABLE | \
4914 DUK_PROPDESC_FLAG_CONFIGURABLE)
4915
4916/* flags for duk_hobject_get_own_propdesc() and variants */
4917#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */
4918#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */
4919
4920/*
4921 * Macro for object validity check
4922 *
4923 * Assert for currently guaranteed relations between flags, for instance.
4924 */
4925
4926#define DUK_ASSERT_HOBJECT_VALID(h) do { \
4927 DUK_ASSERT((h) != NULL); \
4928 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \
4929 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \
4930 DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \
4931 (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \
4932 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
4933 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \
4934 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \
4935 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \
4936 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \
4937 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \
4938 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \
4939 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \
4940 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \
4941 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \
4942 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \
4943 } while (0)
4944
4945/*
4946 * Macros to access the 'props' allocation.
4947 */
4948
4949#if defined(DUK_USE_HEAPPTR16)
4950#define DUK_HOBJECT_GET_PROPS(heap,h) \
4951 ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16))
4952#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
4953 ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
4954 } while (0)
4955#else
4956#define DUK_HOBJECT_GET_PROPS(heap,h) \
4957 ((h)->props)
4958#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
4959 (h)->props = (duk_uint8_t *) (x); \
4960 } while (0)
4961#endif
4962
4963#if defined(DUK_USE_HOBJECT_LAYOUT_1)
4964/* LAYOUT 1 */
4965#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
4966 ((duk_hstring **) (void *) ( \
4967 DUK_HOBJECT_GET_PROPS((heap), (h)) \
4968 ))
4969#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
4970 ((duk_propvalue *) (void *) ( \
4971 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
4972 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \
4973 ))
4974#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
4975 ((duk_uint8_t *) (void *) ( \
4976 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
4977 ))
4978#define DUK_HOBJECT_A_GET_BASE(heap,h) \
4979 ((duk_tval *) (void *) ( \
4980 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
4981 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
4982 ))
4983#define DUK_HOBJECT_H_GET_BASE(heap,h) \
4984 ((duk_uint32_t *) (void *) ( \
4985 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
4986 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
4987 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
4988 ))
4989#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
4990 ( \
4991 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
4992 (n_arr) * sizeof(duk_tval) + \
4993 (n_hash) * sizeof(duk_uint32_t) \
4994 )
4995#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 { \
4996 (set_e_k) = (duk_hstring **) (void *) (p_base); \
4997 (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \
4998 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \
4999 (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \
5000 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
5001 } while (0)
5002#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
5003/* LAYOUT 2 */
5004#if (DUK_USE_ALIGN_BY == 4)
5005#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
5006#elif (DUK_USE_ALIGN_BY == 8)
5007#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
5008#elif (DUK_USE_ALIGN_BY == 1)
5009#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
5010#else
5011#error invalid DUK_USE_ALIGN_BY
5012#endif
5013#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
5014 ((duk_hstring **) (void *) ( \
5015 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5016 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
5017 ))
5018#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
5019 ((duk_propvalue *) (void *) ( \
5020 DUK_HOBJECT_GET_PROPS((heap), (h)) \
5021 ))
5022#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
5023 ((duk_uint8_t *) (void *) ( \
5024 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
5025 ))
5026#define DUK_HOBJECT_A_GET_BASE(heap,h) \
5027 ((duk_tval *) (void *) ( \
5028 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5029 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5030 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \
5031 ))
5032#define DUK_HOBJECT_H_GET_BASE(heap,h) \
5033 ((duk_uint32_t *) (void *) ( \
5034 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5035 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5036 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \
5037 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5038 ))
5039#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
5040 ( \
5041 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5042 DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
5043 (n_arr) * sizeof(duk_tval) + \
5044 (n_hash) * sizeof(duk_uint32_t) \
5045 )
5046#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 { \
5047 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
5048 (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \
5049 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \
5050 (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \
5051 sizeof(duk_uint8_t) * (n_ent) + \
5052 DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
5053 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
5054 } while (0)
5055#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
5056/* LAYOUT 3 */
5057#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
5058 ((duk_hstring **) (void *) ( \
5059 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5060 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \
5061 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5062 ))
5063#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
5064 ((duk_propvalue *) (void *) ( \
5065 DUK_HOBJECT_GET_PROPS((heap), (h)) \
5066 ))
5067#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
5068 ((duk_uint8_t *) (void *) ( \
5069 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5070 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
5071 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \
5072 DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \
5073 ))
5074#define DUK_HOBJECT_A_GET_BASE(heap,h) \
5075 ((duk_tval *) (void *) ( \
5076 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5077 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
5078 ))
5079#define DUK_HOBJECT_H_GET_BASE(heap,h) \
5080 ((duk_uint32_t *) (void *) ( \
5081 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5082 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
5083 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5084 ))
5085#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
5086 ( \
5087 (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
5088 (n_arr) * sizeof(duk_tval) + \
5089 (n_hash) * sizeof(duk_uint32_t) \
5090 )
5091#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 { \
5092 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
5093 (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \
5094 (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \
5095 (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \
5096 (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \
5097 } while (0)
5098#else
5099#error invalid hobject layout defines
5100#endif /* hobject property layout */
5101
5102#define DUK_HOBJECT_P_ALLOC_SIZE(h) \
5103 DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h)))
5104
5105#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
5106#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
5107#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
5108#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
5109#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
5110#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
5111#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
5112#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
5113#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
5114#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
5115#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
5116#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
5117#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
5118#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
5119#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
5120#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
5121
5122#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \
5123 DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \
5124 } while (0)
5125#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \
5126 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \
5127 } while (0)
5128#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \
5129 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \
5130 } while (0)
5131#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \
5132 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \
5133 } while (0)
5134#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \
5135 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
5136 } while (0)
5137#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
5138 DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
5139 } while (0)
5140#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
5141 DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
5142 } while (0)
5143#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \
5144 DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */
5145#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \
5146 DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \
5147 } while (0)
5148
5149#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \
5150 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \
5151 } while (0)
5152
5153#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \
5154 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \
5155 } while (0)
5156
5157#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
5158#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
5159#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
5160#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
5161
5162#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
5163#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
5164#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
5165#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
5166
5167#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
5168#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
5169#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
5170#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
5171
5172#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
5173#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
5174#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
5175#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
5176
5177#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL
5178#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL
5179
5180/*
5181 * Macros for accessing size fields
5182 */
5183
5184#if defined(DUK_USE_OBJSIZES16)
5185#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16)
5186#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0)
5187#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16)
5188#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0)
5189#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++)
5190#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16)
5191#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0)
5192#if defined(DUK_USE_HOBJECT_HASH_PART)
5193#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16)
5194#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0)
5195#else
5196#define DUK_HOBJECT_GET_HSIZE(h) 0
5197#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
5198#endif
5199#else
5200#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size)
5201#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0)
5202#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next)
5203#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0)
5204#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++)
5205#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size)
5206#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0)
5207#if defined(DUK_USE_HOBJECT_HASH_PART)
5208#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size)
5209#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0)
5210#else
5211#define DUK_HOBJECT_GET_HSIZE(h) 0
5212#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
5213#endif
5214#endif
5215
5216/*
5217 * Misc
5218 */
5219
5220/* Maximum prototype traversal depth. Sanity limit which handles e.g.
5221 * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
5222 */
5223#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
5224
5225/* Maximum traversal depth for "bound function" chains. */
5226#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L
5227
5228/*
5229 * Ecmascript [[Class]]
5230 */
5231
5232/* range check not necessary because all 4-bit values are mapped */
5233#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)]
5234
5235#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \
5236 DUK_HEAP_GET_STRING( \
5237 (heap), \
5238 DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
5239 )
5240
5241/*
5242 * Macros for property handling
5243 */
5244
5245#if defined(DUK_USE_HEAPPTR16)
5246#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
5247 ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
5248#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
5249 (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
5250 } while (0)
5251#else
5252#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
5253 ((h)->prototype)
5254#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
5255 (h)->prototype = (x); \
5256 } while (0)
5257#endif
5258
5259/* note: this updates refcounts */
5260#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
5261
5262/*
5263 * Resizing and hash behavior
5264 */
5265
5266/* Sanity limit on max number of properties (allocated, not necessarily used).
5267 * This is somewhat arbitrary, but if we're close to 2**32 properties some
5268 * algorithms will fail (e.g. hash size selection, next prime selection).
5269 * Also, we use negative array/entry table indices to indicate 'not found',
5270 * so anything above 0x80000000 will cause trouble now.
5271 */
5272#if defined(DUK_USE_OBJSIZES16)
5273#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
5274#else
5275#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */
5276#endif
5277
5278/* higher value conserves memory; also note that linear scan is cache friendly */
5279#define DUK_HOBJECT_E_USE_HASH_LIMIT 32
5280
5281/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */
5282#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */
5283
5284/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */
5285#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */
5286
5287/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */
5288/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */
5289#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */
5290
5291/* internal align target for props allocation, must be 2*n for some n */
5292#if (DUK_USE_ALIGN_BY == 4)
5293#define DUK_HOBJECT_ALIGN_TARGET 4
5294#elif (DUK_USE_ALIGN_BY == 8)
5295#define DUK_HOBJECT_ALIGN_TARGET 8
5296#elif (DUK_USE_ALIGN_BY == 1)
5297#define DUK_HOBJECT_ALIGN_TARGET 1
5298#else
5299#error invalid DUK_USE_ALIGN_BY
5300#endif
5301
5302/* controls for minimum entry part growth */
5303#define DUK_HOBJECT_E_MIN_GROW_ADD 16
5304#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
5305
5306/* controls for minimum array part growth */
5307#define DUK_HOBJECT_A_MIN_GROW_ADD 16
5308#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
5309
5310/* probe sequence */
5311#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
5312#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
5313
5314/*
5315 * PC-to-line constants
5316 */
5317
5318#define DUK_PC2LINE_SKIP 64
5319
5320/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
5321#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
5322
5323/*
5324 * Struct defs
5325 */
5326
5327struct duk_propaccessor {
5328 duk_hobject *get;
5329 duk_hobject *set;
5330};
5331
5332union duk_propvalue {
5333 /* The get/set pointers could be 16-bit pointer compressed but it
5334 * would make no difference on 32-bit platforms because duk_tval is
5335 * 8 bytes or more anyway.
5336 */
5337 duk_tval v;
5338 duk_propaccessor a;
5339};
5340
5341struct duk_propdesc {
5342 /* read-only values 'lifted' for ease of use */
5343 duk_small_int_t flags;
5344 duk_hobject *get;
5345 duk_hobject *set;
5346
5347 /* for updating (all are set to < 0 for virtual properties) */
5348 duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */
5349 duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */
5350 duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */
5351};
5352
5353struct duk_hobject {
5354 duk_heaphdr hdr;
5355
5356 /*
5357 * 'props' contains {key,value,flags} entries, optional array entries, and
5358 * an optional hash lookup table for non-array entries in a single 'sliced'
5359 * allocation. There are several layout options, which differ slightly in
5360 * generated code size/speed and alignment/padding; duk_features.h selects
5361 * the layout used.
5362 *
5363 * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
5364 *
5365 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5366 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5367 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
5368 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5369 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5370 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5371 *
5372 * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
5373 *
5374 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5375 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5376 * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable)
5377 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5378 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5379 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5380 *
5381 * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
5382 *
5383 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5384 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5385 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5386 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5387 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5388 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
5389 *
5390 * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms
5391 * requiring 4 or 8 byte alignment. This ensures proper alignment
5392 * for the entries, at the cost of memory footprint. However, it's
5393 * probably preferable to use another layout on such platforms instead.
5394 *
5395 * In layout 2, the key and value parts are swapped to avoid padding
5396 * the key array on platforms requiring alignment by 8. The flags part
5397 * is padded to get alignment for array entries. The 'e_next' count does
5398 * not need to be rounded as in layout 1.
5399 *
5400 * In layout 3, entry values and array values are always aligned properly,
5401 * and assuming pointers are at most 8 bytes, so are the entry keys. Hash
5402 * indices will be properly aligned (assuming pointers are at least 4 bytes).
5403 * Finally, flags don't need additional alignment. This layout provides
5404 * compact allocations without padding (even on platforms with alignment
5405 * requirements) at the cost of a bit slower lookups.
5406 *
5407 * Objects with few keys don't have a hash index; keys are looked up linearly,
5408 * which is cache efficient because the keys are consecutive. Larger objects
5409 * have a hash index part which contains integer indexes to the entries part.
5410 *
5411 * A single allocation reduces memory allocation overhead but requires more
5412 * work when any part needs to be resized. A sliced allocation for entries
5413 * makes linear key matching faster on most platforms (more locality) and
5414 * skimps on flags size (which would be followed by 3 bytes of padding in
5415 * most architectures if entries were placed in a struct).
5416 *
5417 * 'props' also contains internal properties distinguished with a non-BMP
5418 * prefix. Often used properties should be placed early in 'props' whenever
5419 * possible to make accessing them as fast a possible.
5420 */
5421
5422#if defined(DUK_USE_HEAPPTR16)
5423 /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
5424 * duk_hcompiledfunction) are not free to use h_extra16 for this reason.
5425 */
5426#else
5427 duk_uint8_t *props;
5428#endif
5429
5430 /* prototype: the only internal property lifted outside 'e' as it is so central */
5431#if defined(DUK_USE_HEAPPTR16)
5432 duk_uint16_t prototype16;
5433#else
5434 duk_hobject *prototype;
5435#endif
5436
5437#if defined(DUK_USE_OBJSIZES16)
5438 duk_uint16_t e_size16;
5439 duk_uint16_t e_next16;
5440 duk_uint16_t a_size16;
5441#if defined(DUK_USE_HOBJECT_HASH_PART)
5442 duk_uint16_t h_size16;
5443#endif
5444#else
5445 duk_uint32_t e_size; /* entry part size */
5446 duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */
5447 duk_uint32_t a_size; /* array part size (entirely gc reachable) */
5448#if defined(DUK_USE_HOBJECT_HASH_PART)
5449 duk_uint32_t h_size; /* hash part size or 0 if unused */
5450#endif
5451#endif
5452};
5453
5454/*
5455 * Exposed data
5456 */
5457
5458#if !defined(DUK_SINGLE_FILE)
5459DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
5460#endif /* !DUK_SINGLE_FILE */
5461
5462/*
5463 * Prototypes
5464 */
5465
5466/* alloc and init */
5467DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5468#if 0 /* unused */
5469DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags);
5470#endif
5471DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5472DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5473DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5474DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5475
5476/* low-level property functions */
5477DUK_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);
5478DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
5479DUK_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);
5480DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
5481DUK_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);
5482
5483/* XXX: when optimizing for guaranteed property slots, use a guaranteed
5484 * slot for internal value; this call can then access it directly.
5485 */
5486#define duk_hobject_get_internal_value_tval_ptr(heap,obj) \
5487 duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap)))
5488
5489/* core property functions */
5490DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
5491DUK_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);
5492DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag);
5493DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
5494
5495/* internal property functions */
5496#define DUK_DELPROP_FLAG_THROW (1 << 0)
5497#define DUK_DELPROP_FLAG_FORCE (1 << 1)
5498DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
5499DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
5500DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
5501DUK_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);
5502DUK_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);
5503DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */
5504DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj);
5505DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */
5506
5507/* helpers for defineProperty() and defineProperties() */
5508DUK_INTERNAL_DECL
5509void duk_hobject_prepare_property_descriptor(duk_context *ctx,
5510 duk_idx_t idx_in,
5511 duk_uint_t *out_defprop_flags,
5512 duk_idx_t *out_idx_value,
5513 duk_hobject **out_getter,
5514 duk_hobject **out_setter);
5515DUK_INTERNAL_DECL
5516void duk_hobject_define_property_helper(duk_context *ctx,
5517 duk_uint_t defprop_flags,
5518 duk_hobject *obj,
5519 duk_hstring *key,
5520 duk_idx_t idx_value,
5521 duk_hobject *get,
5522 duk_hobject *set);
5523
5524/* Object built-in methods */
5525DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx);
5526DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
5527DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
5528DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);
5529
5530/* internal properties */
5531DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
5532DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
5533
5534/* hobject management functions */
5535DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
5536
5537/* ES6 proxy */
5538#if defined(DUK_USE_ES6_PROXY)
5539DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
5540DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj);
5541#endif
5542
5543/* enumeration */
5544DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags);
5545DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags);
5546DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value);
5547
5548/* macros */
5549DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
5550
5551/* finalization */
5552DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
5553
5554/* pc2line */
5555#if defined(DUK_USE_PC2LINE)
5556DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
5557DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc);
5558#endif
5559
5560/* misc */
5561DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
5562
5563#endif /* DUK_HOBJECT_H_INCLUDED */
5564#line 1 "duk_hcompiledfunction.h"
5565/*
5566 * Heap compiled function (Ecmascript function) representation.
5567 *
5568 * There is a single data buffer containing the Ecmascript function's
5569 * bytecode, constants, and inner functions.
5570 */
5571
5572#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED
5573#define DUK_HCOMPILEDFUNCTION_H_INCLUDED
5574
5575/*
5576 * Field accessor macros
5577 */
5578
5579/* XXX: casts could be improved, especially for GET/SET DATA */
5580
5581#if defined(DUK_USE_HEAPPTR16)
5582#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
5583 ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
5584#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
5585 (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
5586 } while (0)
5587#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
5588 ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
5589#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
5590 (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
5591 } while (0)
5592#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
5593 ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
5594#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
5595 (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
5596 } while (0)
5597#else
5598#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
5599 ((duk_hbuffer_fixed *) (void *) (h)->data)
5600#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
5601 (h)->data = (duk_hbuffer *) (v); \
5602 } while (0)
5603#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
5604 ((h)->funcs)
5605#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
5606 (h)->funcs = (v); \
5607 } while (0)
5608#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
5609 ((h)->bytecode)
5610#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
5611 (h)->bytecode = (v); \
5612 } while (0)
5613#endif
5614
5615/*
5616 * Accessor macros for function specific data areas
5617 */
5618
5619/* Note: assumes 'data' is always a fixed buffer */
5620#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h) \
5621 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h)))
5622
5623#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h) \
5624 ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h)))
5625
5626#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h) \
5627 DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))
5628
5629#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h) \
5630 DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))
5631
5632#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h) \
5633 ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)))
5634
5635#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h) \
5636 ((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)))
5637
5638/* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */
5639#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h) \
5640 ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \
5641 DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h))))
5642
5643#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h) \
5644 ( \
5645 (duk_size_t) \
5646 ( \
5647 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \
5648 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \
5649 ) \
5650 )
5651
5652#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h) \
5653 ( \
5654 (duk_size_t) \
5655 ( \
5656 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \
5657 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \
5658 ) \
5659 )
5660
5661#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h) \
5662 ( \
5663 (duk_size_t) \
5664 ( \
5665 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \
5666 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \
5667 ) \
5668 )
5669
5670#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h) \
5671 ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
5672
5673#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h) \
5674 ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
5675
5676#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h) \
5677 ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
5678
5679
5680/*
5681 * Main struct
5682 */
5683
5684struct duk_hcompiledfunction {
5685 /* shared object part */
5686 duk_hobject obj;
5687
5688 /*
5689 * Pointers to function data area for faster access. Function
5690 * data is a buffer shared between all closures of the same
5691 * "template" function. The data buffer is always fixed (non-
5692 * dynamic, hence stable), with a layout as follows:
5693 *
5694 * constants (duk_tval)
5695 * inner functions (duk_hobject *)
5696 * bytecode (duk_instr_t)
5697 *
5698 * Note: bytecode end address can be computed from 'data' buffer
5699 * size. It is not strictly necessary functionally, assuming
5700 * bytecode never jumps outside its allocated area. However,
5701 * it's a safety/robustness feature for avoiding the chance of
5702 * executing random data as bytecode due to a compiler error.
5703 *
5704 * Note: values in the data buffer must be incref'd (they will
5705 * be decref'd on release) for every compiledfunction referring
5706 * to the 'data' element.
5707 */
5708
5709 /* Data area, fixed allocation, stable data ptrs. */
5710#if defined(DUK_USE_HEAPPTR16)
5711 duk_uint16_t data16;
5712#else
5713 duk_hbuffer *data;
5714#endif
5715
5716 /* No need for constants pointer (= same as data).
5717 *
5718 * When using 16-bit packing alignment to 4 is nice. 'funcs' will be
5719 * 4-byte aligned because 'constants' are duk_tvals. For now the
5720 * inner function pointers are not compressed, so that 'bytecode' will
5721 * also be 4-byte aligned.
5722 */
5723#if defined(DUK_USE_HEAPPTR16)
5724 duk_uint16_t funcs16;
5725 duk_uint16_t bytecode16;
5726#else
5727 duk_hobject **funcs;
5728 duk_instr_t *bytecode;
5729#endif
5730
5731 /*
5732 * 'nregs' registers are allocated on function entry, at most 'nargs'
5733 * are initialized to arguments, and the rest to undefined. Arguments
5734 * above 'nregs' are not mapped to registers. All registers in the
5735 * active stack range must be initialized because they are GC reachable.
5736 * 'nargs' is needed so that if the function is given more than 'nargs'
5737 * arguments, the additional arguments do not 'clobber' registers
5738 * beyond 'nregs' which must be consistently initialized to undefined.
5739 *
5740 * Usually there is no need to know which registers are mapped to
5741 * local variables. Registers may be allocated to variable in any
5742 * way (even including gaps). However, a register-variable mapping
5743 * must be the same for the duration of the function execution and
5744 * the register cannot be used for anything else.
5745 *
5746 * When looking up variables by name, the '_Varmap' map is used.
5747 * When an activation closes, registers mapped to arguments are
5748 * copied into the environment record based on the same map. The
5749 * reverse map (from register to variable) is not currently needed
5750 * at run time, except for debugging, so it is not maintained.
5751 */
5752
5753 duk_uint16_t nregs; /* regs to allocate */
5754 duk_uint16_t nargs; /* number of arguments allocated to regs */
5755
5756 /*
5757 * Additional control information is placed into the object itself
5758 * as internal properties to avoid unnecessary fields for the
5759 * majority of functions. The compiler tries to omit internal
5760 * control fields when possible.
5761 *
5762 * Function templates:
5763 *
5764 * {
5765 * name: "func", // declaration, named function expressions
5766 * fileName: <debug info for creating nice errors>
5767 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
5768 * _Formals: [ "arg1", "arg2" ],
5769 * _Source: "function func(arg1, arg2) { ... }",
5770 * _Pc2line: <debug info for pc-to-line mapping>,
5771 * }
5772 *
5773 * Function instances:
5774 *
5775 * {
5776 * length: 2,
5777 * prototype: { constructor: <func> },
5778 * caller: <thrower>,
5779 * arguments: <thrower>,
5780 * name: "func", // declaration, named function expressions
5781 * fileName: <debug info for creating nice errors>
5782 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
5783 * _Formals: [ "arg1", "arg2" ],
5784 * _Source: "function func(arg1, arg2) { ... }",
5785 * _Pc2line: <debug info for pc-to-line mapping>,
5786 * _Varenv: <variable environment of closure>,
5787 * _Lexenv: <lexical environment of closure (if differs from _Varenv)>
5788 * }
5789 *
5790 * More detailed description of these properties can be found
5791 * in the documentation.
5792 */
5793
5794#if defined(DUK_USE_DEBUGGER_SUPPORT)
5795 /* Line number range for function. Needed during debugging to
5796 * determine active breakpoints.
5797 */
5798 duk_uint32_t start_line;
5799 duk_uint32_t end_line;
5800#endif
5801};
5802
5803#endif /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */
5804#line 1 "duk_hnativefunction.h"
5805/*
5806 * Heap native function representation.
5807 */
5808
5809#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED
5810#define DUK_HNATIVEFUNCTION_H_INCLUDED
5811
5812#define DUK_HNATIVEFUNCTION_NARGS_VARARGS ((duk_int16_t) -1)
5813#define DUK_HNATIVEFUNCTION_NARGS_MAX ((duk_int16_t) 0x7fff)
5814
5815struct duk_hnativefunction {
5816 /* shared object part */
5817 duk_hobject obj;
5818
5819 duk_c_function func;
5820 duk_int16_t nargs;
5821 duk_int16_t magic;
5822
5823 /* The 'magic' field allows an opaque 16-bit field to be accessed by the
5824 * Duktape/C function. This allows, for instance, the same native function
5825 * to be used for a set of very similar functions, with the 'magic' field
5826 * providing the necessary non-argument flags / values to guide the behavior
5827 * of the native function. The value is signed on purpose: it is easier to
5828 * convert a signed value to unsigned (simply AND with 0xffff) than vice
5829 * versa.
5830 *
5831 * Note: cannot place nargs/magic into the heaphdr flags, because
5832 * duk_hobject takes almost all flags already (and needs the spare).
5833 */
5834};
5835
5836#endif /* DUK_HNATIVEFUNCTION_H_INCLUDED */
5837#line 1 "duk_hbufferobject.h"
5838/*
5839 * Heap Buffer object representation. Used for all Buffer variants.
5840 */
5841
5842#ifndef DUK_HBUFFEROBJECT_H_INCLUDED
5843#define DUK_HBUFFEROBJECT_H_INCLUDED
5844
5845/* All element accessors are host endian now (driven by TypedArray spec). */
5846#define DUK_HBUFFEROBJECT_ELEM_UINT8 0
5847#define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1
5848#define DUK_HBUFFEROBJECT_ELEM_INT8 2
5849#define DUK_HBUFFEROBJECT_ELEM_UINT16 3
5850#define DUK_HBUFFEROBJECT_ELEM_INT16 4
5851#define DUK_HBUFFEROBJECT_ELEM_UINT32 5
5852#define DUK_HBUFFEROBJECT_ELEM_INT32 6
5853#define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7
5854#define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8
5855#define DUK_HBUFFEROBJECT_ELEM_MAX 8
5856
5857#define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \
5858 DUK_ASSERT((h) != NULL); \
5859 DUK_ASSERT((h)->shift <= 3); \
5860 DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \
5861 DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \
5862 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \
5863 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \
5864 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \
5865 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \
5866 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \
5867 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \
5868 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \
5869 ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \
5870 DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \
5871 DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \
5872 if ((h)->buf == NULL) { \
5873 DUK_ASSERT((h)->offset == 0); \
5874 DUK_ASSERT((h)->length == 0); \
5875 } else { \
5876 /* No assertions for offset or length; in particular, \
5877 * it's OK for length to be longer than underlying \
5878 * buffer. Just ensure they don't wrap when added. \
5879 */ \
5880 DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \
5881 } \
5882 } while (0)
5883
5884/* Get the current data pointer (caller must ensure buf != NULL) as a
5885 * duk_uint8_t ptr.
5886 */
5887#define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \
5888 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5889 (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
5890
5891/* True if slice is full, i.e. offset is zero and length covers the entire
5892 * buffer. This status may change independently of the duk_hbufferobject if
5893 * the underlying buffer is dynamic and changes without the hbufferobject
5894 * being changed.
5895 */
5896#define DUK_HBUFFEROBJECT_FULL_SLICE(h) \
5897 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5898 ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
5899
5900/* Validate that the whole slice [0,length[ is contained in the underlying
5901 * buffer. Caller must ensure 'buf' != NULL.
5902 */
5903#define DUK_HBUFFEROBJECT_VALID_SLICE(h) \
5904 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5905 ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
5906
5907/* Validate byte read/write for virtual 'offset', i.e. check that the
5908 * offset, taking into account h->offset, is within the underlying
5909 * buffer size. This is a safety check which is needed to ensure
5910 * that even a misconfigured duk_hbufferobject never causes memory
5911 * unsafe behavior (e.g. if an underlying dynamic buffer changes
5912 * after being setup). Caller must ensure 'buf' != NULL.
5913 */
5914#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \
5915 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5916 ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
5917
5918#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \
5919 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5920 ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
5921
5922/* Clamp an input byte length (already assumed to be within the nominal
5923 * duk_hbufferobject 'length') to the current dynamic buffer limits to
5924 * yield a byte length limit that's safe for memory accesses. This value
5925 * can be invalidated by any side effect because it may trigger a user
5926 * callback that resizes the underlying buffer.
5927 */
5928#define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \
5929 (DUK_ASSERT_EXPR((h) != NULL), \
5930 duk_hbufferobject_clamp_bytelength((h), (len)))
5931
5932struct duk_hbufferobject {
5933 /* Shared object part. */
5934 duk_hobject obj;
5935
5936 /* Underlying buffer (refcounted), may be NULL. */
5937 duk_hbuffer *buf;
5938
5939 /* Slice and accessor information.
5940 *
5941 * Because the underlying buffer may be dynamic, these may be
5942 * invalidated by the buffer being modified so that both offset
5943 * and length should be validated before every access. Behavior
5944 * when the underlying buffer has changed doesn't need to be clean:
5945 * virtual 'length' doesn't need to be affected, reads can return
5946 * zero/NaN, and writes can be ignored.
5947 *
5948 * Note that a data pointer cannot be precomputed because 'buf' may
5949 * be dynamic and its pointer unstable.
5950 */
5951
5952 duk_uint_t offset; /* byte offset to buf */
5953 duk_uint_t length; /* byte index limit for element access, exclusive */
5954 duk_uint8_t shift; /* element size shift:
5955 * 0 = u8/i8
5956 * 1 = u16/i16
5957 * 2 = u32/i32/float
5958 * 3 = double
5959 */
5960 duk_uint8_t elem_type; /* element type */
5961 duk_uint8_t is_view;
5962};
5963
5964#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
5965DUK_INTERNAL_DECL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len);
5966#endif
5967DUK_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);
5968DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
5969
5970#endif /* DUK_HBUFFEROBJECT_H_INCLUDED */
5971#line 1 "duk_hthread.h"
5972/*
5973 * Heap thread object representation.
5974 *
5975 * duk_hthread is also the 'context' (duk_context) for exposed APIs
5976 * which mostly operate on the topmost frame of the value stack.
5977 */
5978
5979#ifndef DUK_HTHREAD_H_INCLUDED
5980#define DUK_HTHREAD_H_INCLUDED
5981
5982/*
5983 * Stack constants
5984 */
5985
5986#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */
5987#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */
5988#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */
5989#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
5990#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry,
5991 * always added to user-defined 'extra' for e.g. the
5992 * duk_check_stack() call.
5993 */
5994#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
5995 /* number of elements guaranteed to be user accessible
5996 * (in addition to call arguments) on Duktape/C function entry.
5997 */
5998
5999/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
6000 * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
6001 * requirements.
6002 */
6003
6004#define DUK_VALSTACK_DEFAULT_MAX 1000000L
6005
6006#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */
6007#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */
6008#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */
6009#define DUK_CALLSTACK_INITIAL_SIZE 8
6010#define DUK_CALLSTACK_DEFAULT_MAX 10000L
6011
6012#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */
6013#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */
6014#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */
6015#define DUK_CATCHSTACK_INITIAL_SIZE 4
6016#define DUK_CATCHSTACK_DEFAULT_MAX 10000L
6017
6018/*
6019 * Activation defines
6020 */
6021
6022#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */
6023#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */
6024#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */
6025#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */
6026#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */
6027#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */
6028
6029#define DUK_ACT_GET_FUNC(act) ((act)->func)
6030
6031/*
6032 * Flags for __FILE__ / __LINE__ registered into tracedata
6033 */
6034
6035#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
6036
6037/*
6038 * Catcher defines
6039 */
6040
6041/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
6042#define DUK_CAT_TYPE_MASK 0x0000000fUL
6043#define DUK_CAT_TYPE_BITS 4
6044#define DUK_CAT_LABEL_MASK 0xffffff00UL
6045#define DUK_CAT_LABEL_BITS 24
6046#define DUK_CAT_LABEL_SHIFT 8
6047
6048#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */
6049#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */
6050#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */
6051#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */
6052
6053#define DUK_CAT_TYPE_UNKNOWN 0
6054#define DUK_CAT_TYPE_TCF 1
6055#define DUK_CAT_TYPE_LABEL 2
6056
6057#define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK)
6058#define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT)
6059
6060#define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED)
6061#define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED)
6062#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED)
6063#define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE)
6064
6065#define DUK_CAT_SET_CATCH_ENABLED(c) do { \
6066 (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \
6067 } while (0)
6068#define DUK_CAT_SET_FINALLY_ENABLED(c) do { \
6069 (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \
6070 } while (0)
6071#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \
6072 (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
6073 } while (0)
6074#define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \
6075 (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \
6076 } while (0)
6077
6078#define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \
6079 (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \
6080 } while (0)
6081#define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \
6082 (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \
6083 } while (0)
6084#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \
6085 (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
6086 } while (0)
6087#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \
6088 (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \
6089 } while (0)
6090
6091/*
6092 * Thread defines
6093 */
6094
6095#if defined(DUK_USE_ROM_STRINGS)
6096#define DUK_HTHREAD_GET_STRING(thr,idx) \
6097 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
6098#else /* DUK_USE_ROM_STRINGS */
6099#if defined(DUK_USE_HEAPPTR16)
6100#define DUK_HTHREAD_GET_STRING(thr,idx) \
6101 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)]))
6102#else
6103#define DUK_HTHREAD_GET_STRING(thr,idx) \
6104 ((thr)->strs[(idx)])
6105#endif
6106#endif /* DUK_USE_ROM_STRINGS */
6107
6108#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1])
6109
6110/* values for the state field */
6111#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */
6112#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */
6113#define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */
6114#define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */
6115#define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */
6116
6117/* Executor interrupt default interval when nothing else requires a
6118 * smaller value. The default interval must be small enough to allow
6119 * for reasonable execution timeout checking but large enough to keep
6120 * impact on execution performance low.
6121 */
6122#if defined(DUK_USE_INTERRUPT_COUNTER)
6123#define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L)
6124#endif
6125
6126/*
6127 * Assert context is valid: non-NULL pointer, fields look sane.
6128 *
6129 * This is used by public API call entrypoints to catch invalid 'ctx' pointers
6130 * as early as possible; invalid 'ctx' pointers cause very odd and difficult to
6131 * diagnose behavior so it's worth checking even when the check is not 100%.
6132 */
6133
6134#if defined(DUK_USE_PREFER_SIZE)
6135#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/
6136#else
6137#define DUK_ASSERT_CTX_VSSIZE(ctx) \
6138 DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \
6139 ((duk_hthread *) (ctx))->valstack_size)
6140#endif
6141#define DUK_ASSERT_CTX_VALID(ctx) do { \
6142 DUK_ASSERT((ctx) != NULL); \
6143 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \
6144 DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \
6145 DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \
6146 DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \
6147 DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \
6148 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \
6149 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \
6150 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \
6151 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \
6152 DUK_ASSERT_CTX_VSSIZE((ctx)); \
6153 } while (0)
6154
6155/*
6156 * Struct defines
6157 */
6158
6159/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function
6160 * or a macro. This would make the activation 32 bytes long on 32-bit platforms again.
6161 */
6162
6163/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */
6164struct duk_activation {
6165 duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
6166 duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
6167 duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
6168 duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
6169#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
6170 /* Previous value of 'func' caller, restored when unwound. Only in use
6171 * when 'func' is non-strict.
6172 */
6173 duk_hobject *prev_caller;
6174#endif
6175
6176 duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
6177#if defined(DUK_USE_DEBUGGER_SUPPORT)
6178 duk_uint32_t prev_line; /* needed for stepping */
6179#endif
6180 duk_small_uint_t flags;
6181
6182 /* idx_bottom and idx_retval are only used for book-keeping of
6183 * Ecmascript-initiated calls, to allow returning to an Ecmascript
6184 * function properly. They are duk_size_t to match the convention
6185 * that value stack sizes are duk_size_t and local frame indices
6186 * are duk_idx_t.
6187 */
6188
6189 /* Bottom of valstack for this activation, used to reset
6190 * valstack_bottom on return; index is absolute. Note:
6191 * idx_top not needed because top is set to 'nregs' always
6192 * when returning to an Ecmascript activation.
6193 */
6194 duk_size_t idx_bottom;
6195
6196 /* Return value when returning to this activation (points to caller
6197 * reg, not callee reg); index is absolute (only set if activation is
6198 * not topmost).
6199 *
6200 * Note: idx_bottom is always set, while idx_retval is only applicable
6201 * for activations below the topmost one. Currently idx_retval for
6202 * the topmost activation is considered garbage (and it not initialized
6203 * on entry or cleared on return; may contain previous or garbage
6204 * values).
6205 */
6206 duk_size_t idx_retval;
6207
6208 /* Current 'this' binding is the value just below idx_bottom.
6209 * Previously, 'this' binding was handled with an index to the
6210 * (calling) valstack. This works for everything except tail
6211 * calls, which must not "cumulate" valstack temps.
6212 */
6213};
6214
6215/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
6216struct duk_catcher {
6217 duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
6218 /* (reference is valid as long activation exists) */
6219 duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
6220 duk_size_t callstack_index; /* callstack index of related activation */
6221 duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
6222 duk_uint32_t flags; /* type and control flags, label number */
6223};
6224
6225struct duk_hthread {
6226 /* Shared object part */
6227 duk_hobject obj;
6228
6229 /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy
6230 * the current PC back into the topmost activation when activation
6231 * state is about to change (or "syncing" is otherwise needed). This
6232 * is rather awkward but important for performance, see execution.rst.
6233 */
6234 duk_instr_t **ptr_curr_pc;
6235
6236 /* Backpointers. */
6237 duk_heap *heap;
6238
6239 /* Current strictness flag: affects API calls. */
6240 duk_uint8_t strict;
6241
6242 /* Thread state. */
6243 duk_uint8_t state;
6244 duk_uint8_t unused1;
6245 duk_uint8_t unused2;
6246
6247 /* Sanity limits for stack sizes. */
6248 duk_size_t valstack_max;
6249 duk_size_t callstack_max;
6250 duk_size_t catchstack_max;
6251
6252 /* XXX: Valstack, callstack, and catchstack are currently assumed
6253 * to have non-NULL pointers. Relaxing this would not lead to big
6254 * benefits (except perhaps for terminated threads).
6255 */
6256
6257 /* Value stack: these are expressed as pointers for faster stack manipulation.
6258 * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is
6259 * not GC-reachable but kept initialized as 'undefined'.
6260 */
6261 duk_tval *valstack; /* start of valstack allocation */
6262 duk_tval *valstack_end; /* end of valstack allocation (exclusive) */
6263 duk_tval *valstack_bottom; /* bottom of current frame */
6264 duk_tval *valstack_top; /* top of current frame (exclusive) */
6265#if !defined(DUK_USE_PREFER_SIZE)
6266 duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */
6267#endif
6268
6269 /* Call stack. [0,callstack_top[ is GC reachable. */
6270 duk_activation *callstack;
6271 duk_size_t callstack_size; /* allocation size */
6272 duk_size_t callstack_top; /* next to use, highest used is top - 1 */
6273 duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
6274
6275 /* Catch stack. [0,catchstack_top[ is GC reachable. */
6276 duk_catcher *catchstack;
6277 duk_size_t catchstack_size; /* allocation size */
6278 duk_size_t catchstack_top; /* next to use, highest used is top - 1 */
6279
6280 /* Yield/resume book-keeping. */
6281 duk_hthread *resumer; /* who resumed us (if any) */
6282
6283 /* Current compiler state (if any), used for augmenting SyntaxErrors. */
6284 duk_compiler_ctx *compile_ctx;
6285
6286#if defined(DUK_USE_INTERRUPT_COUNTER)
6287 /* Interrupt counter for triggering a slow path check for execution
6288 * timeout, debugger interaction such as breakpoints, etc. The value
6289 * is valid for the current running thread, and both the init and
6290 * counter values are copied whenever a thread switch occurs. It's
6291 * important for the counter to be conveniently accessible for the
6292 * bytecode executor inner loop for performance reasons.
6293 */
6294 duk_int_t interrupt_counter; /* countdown state */
6295 duk_int_t interrupt_init; /* start value for current countdown */
6296#endif
6297
6298 /* Builtin-objects; may or may not be shared with other threads,
6299 * threads existing in different "compartments" will have different
6300 * built-ins. Must be stored on a per-thread basis because there
6301 * is no intermediate structure for a thread group / compartment.
6302 * This takes quite a lot of space, currently 43x4 = 172 bytes on
6303 * 32-bit platforms.
6304 *
6305 * In some cases the builtins array could be ROM based, but it's
6306 * sometimes edited (e.g. for sandboxing) so it's better to keep
6307 * this array in RAM.
6308 */
6309 duk_hobject *builtins[DUK_NUM_BUILTINS];
6310
6311 /* Convenience copies from heap/vm for faster access. */
6312#if defined(DUK_USE_ROM_STRINGS)
6313 /* No field needed when strings are in ROM. */
6314#else
6315#if defined(DUK_USE_HEAPPTR16)
6316 duk_uint16_t *strs16;
6317#else
6318 duk_hstring **strs;
6319#endif
6320#endif
6321};
6322
6323/*
6324 * Prototypes
6325 */
6326
6327DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to);
6328DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
6329DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
6330DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
6331
6332DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr);
6333DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr);
6334DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top);
6335DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr);
6336DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
6337DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top);
6338
6339DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr);
6340DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6341DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6342DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6343
6344#if defined(DUK_USE_DEBUGGER_SUPPORT)
6345DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
6346#endif
6347DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act);
6348DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
6349DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
6350
6351#endif /* DUK_HTHREAD_H_INCLUDED */
6352#line 1 "duk_hbuffer.h"
6353/*
6354 * Heap buffer representation.
6355 *
6356 * Heap allocated user data buffer which is either:
6357 *
6358 * 1. A fixed size buffer (data follows header statically)
6359 * 2. A dynamic size buffer (data pointer follows header)
6360 *
6361 * The data pointer for a variable size buffer of zero size may be NULL.
6362 */
6363
6364#ifndef DUK_HBUFFER_H_INCLUDED
6365#define DUK_HBUFFER_H_INCLUDED
6366
6367/*
6368 * Flags
6369 *
6370 * Fixed buffer: 0
6371 * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC
6372 * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL
6373 */
6374
6375#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */
6376#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */
6377
6378#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
6379#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
6380
6381#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
6382#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
6383
6384#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
6385#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
6386
6387/*
6388 * Misc defines
6389 */
6390
6391/* Impose a maximum buffer length for now. Restricted artificially to
6392 * ensure resize computations or adding a heap header length won't
6393 * overflow size_t and that a signed duk_int_t can hold a buffer
6394 * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN.
6395 */
6396
6397#if defined(DUK_USE_BUFLEN16)
6398#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL)
6399#else
6400/* Intentionally not 0x7fffffffUL; at least JSON code expects that
6401 * 2*len + 2 fits in 32 bits.
6402 */
6403#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL)
6404#endif
6405
6406/*
6407 * Field access
6408 */
6409
6410/* Get/set the current user visible size, without accounting for a dynamic
6411 * buffer's "spare" (= usable size).
6412 */
6413#if defined(DUK_USE_BUFLEN16)
6414/* size stored in duk_heaphdr unused flag bits */
6415#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
6416#define DUK_HBUFFER_SET_SIZE(x,v) do { \
6417 duk_size_t duk__v; \
6418 duk__v = (v); \
6419 DUK_ASSERT(duk__v <= 0xffffUL); \
6420 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \
6421 } while (0)
6422#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
6423 (x)->hdr.h_flags += ((dv) << 16); \
6424 } while (0)
6425#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
6426 (x)->hdr.h_flags -= ((dv) << 16); \
6427 } while (0)
6428#else
6429#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size)
6430#define DUK_HBUFFER_SET_SIZE(x,v) do { \
6431 ((duk_hbuffer *) (x))->size = (v); \
6432 } while (0)
6433#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
6434 (x)->size += (dv); \
6435 } while (0)
6436#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
6437 (x)->size -= (dv); \
6438 } while (0)
6439#endif
6440
6441#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
6442#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x))
6443
6444#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
6445#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
6446#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv))
6447#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv))
6448
6449#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
6450#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
6451
6452#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1))
6453
6454#if defined(DUK_USE_HEAPPTR16)
6455#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
6456 ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16))
6457#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
6458 ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
6459 } while (0)
6460#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
6461 ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \
6462 } while (0)
6463#else
6464#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc)
6465#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
6466 (x)->curr_alloc = (void *) (v); \
6467 } while (0)
6468#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
6469 (x)->curr_alloc = (void *) NULL; \
6470 } while (0)
6471#endif
6472
6473/* No pointer compression because pointer is potentially outside of
6474 * Duktape heap.
6475 */
6476#if defined(DUK_USE_HEAPPTR16)
6477#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
6478 ((void *) (x)->curr_alloc)
6479#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
6480 (x)->curr_alloc = (void *) (v); \
6481 } while (0)
6482#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
6483 (x)->curr_alloc = (void *) NULL; \
6484 } while (0)
6485#else
6486#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
6487 ((void *) (x)->curr_alloc)
6488#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
6489 (x)->curr_alloc = (void *) (v); \
6490 } while (0)
6491#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
6492 (x)->curr_alloc = (void *) NULL; \
6493 } while (0)
6494#endif
6495
6496/* Get a pointer to the current buffer contents (matching current allocation
6497 * size). May be NULL for zero size dynamic/external buffer.
6498 */
6499#if defined(DUK_USE_HEAPPTR16)
6500#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
6501 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
6502 ( \
6503 DUK_HBUFFER_HAS_EXTERNAL((x)) ? \
6504 DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
6505 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
6506 ) : \
6507 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
6508 )
6509#else
6510/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
6511 * have the same layout so checking for fixed vs. dynamic (or external) is enough.
6512 */
6513#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
6514 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
6515 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
6516 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
6517 )
6518#endif
6519
6520/*
6521 * Structs
6522 */
6523
6524/* Shared prefix for all buffer types. */
6525struct duk_hbuffer {
6526 duk_heaphdr hdr;
6527
6528 /* It's not strictly necessary to track the current size, but
6529 * it is useful for writing robust native code.
6530 */
6531
6532 /* Current size (not counting a dynamic buffer's "spare"). */
6533#if defined(DUK_USE_BUFLEN16)
6534 /* Stored in duk_heaphdr unused flags. */
6535#else
6536 duk_size_t size;
6537#endif
6538
6539 /*
6540 * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
6541 * flag.
6542 *
6543 * If the flag is clear (the buffer is a fixed size one), the buffer
6544 * data follows the header directly, consisting of 'size' bytes.
6545 *
6546 * If the flag is set, the actual buffer is allocated separately, and
6547 * a few control fields follow the header. Specifically:
6548 *
6549 * - a "void *" pointing to the current allocation
6550 * - a duk_size_t indicating the full allocated size (always >= 'size')
6551 *
6552 * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated
6553 * by user code, so that Duktape won't be able to resize it and won't
6554 * free it. This allows buffers to point to e.g. an externally
6555 * allocated structure such as a frame buffer.
6556 *
6557 * Unlike strings, no terminator byte (NUL) is guaranteed after the
6558 * data. This would be convenient, but would pad aligned user buffers
6559 * unnecessarily upwards in size. For instance, if user code requested
6560 * a 64-byte dynamic buffer, 65 bytes would actually be allocated which
6561 * would then potentially round upwards to perhaps 68 or 72 bytes.
6562 */
6563};
6564
6565/* Fixed buffer; data follows struct, with proper alignment guaranteed by
6566 * struct size.
6567 */
6568#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
6569#pragma pack(push, 8)
6570#endif
6571struct duk_hbuffer_fixed {
6572 /* A union is used here as a portable struct size / alignment trick:
6573 * by adding a 32-bit or a 64-bit (unused) union member, the size of
6574 * the struct is effectively forced to be a multiple of 4 or 8 bytes
6575 * (respectively) without increasing the size of the struct unless
6576 * necessary.
6577 */
6578 union {
6579 struct {
6580 duk_heaphdr hdr;
6581#if defined(DUK_USE_BUFLEN16)
6582 /* Stored in duk_heaphdr unused flags. */
6583#else
6584 duk_size_t size;
6585#endif
6586 } s;
6587#if (DUK_USE_ALIGN_BY == 4)
6588 duk_uint32_t dummy_for_align4;
6589#elif (DUK_USE_ALIGN_BY == 8)
6590 duk_double_t dummy_for_align8;
6591#elif (DUK_USE_ALIGN_BY == 1)
6592 /* no extra padding */
6593#else
6594#error invalid DUK_USE_ALIGN_BY
6595#endif
6596 } u;
6597
6598 /*
6599 * Data follows the struct header. The struct size is padded by the
6600 * compiler based on the struct members. This guarantees that the
6601 * buffer data will be aligned-by-4 but not necessarily aligned-by-8.
6602 *
6603 * On platforms where alignment does not matter, the struct padding
6604 * could be removed (if there is any). On platforms where alignment
6605 * by 8 is required, the struct size must be forced to be a multiple
6606 * of 8 by some means. Without it, some user code may break, and also
6607 * Duktape itself breaks (e.g. the compiler stores duk_tvals in a
6608 * dynamic buffer).
6609 */
6610}
6611#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
6612__attribute__ ((aligned (8)))
6613#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
6614__attribute__ ((aligned (8)))
6615#endif
6616;
6617#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
6618#pragma pack(pop)
6619#endif
6620
6621/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using
6622 * heap allocation primitives. Also used for external buffers when low memory
6623 * options are not used.
6624 */
6625struct duk_hbuffer_dynamic {
6626 duk_heaphdr hdr;
6627
6628#if defined(DUK_USE_BUFLEN16)
6629 /* Stored in duk_heaphdr unused flags. */
6630#else
6631 duk_size_t size;
6632#endif
6633
6634#if defined(DUK_USE_HEAPPTR16)
6635 /* Stored in duk_heaphdr h_extra16. */
6636#else
6637 void *curr_alloc; /* may be NULL if alloc_size == 0 */
6638#endif
6639
6640 /*
6641 * Allocation size for 'curr_alloc' is alloc_size. There is no
6642 * automatic NUL terminator for buffers (see above for rationale).
6643 *
6644 * 'curr_alloc' is explicitly allocated with heap allocation
6645 * primitives and will thus always have alignment suitable for
6646 * e.g. duk_tval and an IEEE double.
6647 */
6648};
6649
6650/* External buffer with 'curr_alloc' managed by user code and pointing to an
6651 * arbitrary address. When heap pointer compression is not used, this struct
6652 * has the same layout as duk_hbuffer_dynamic.
6653 */
6654struct duk_hbuffer_external {
6655 duk_heaphdr hdr;
6656
6657#if defined(DUK_USE_BUFLEN16)
6658 /* Stored in duk_heaphdr unused flags. */
6659#else
6660 duk_size_t size;
6661#endif
6662
6663 /* Cannot be compressed as a heap pointer because may point to
6664 * an arbitrary address.
6665 */
6666 void *curr_alloc; /* may be NULL if alloc_size == 0 */
6667};
6668
6669/*
6670 * Prototypes
6671 */
6672
6673DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata);
6674DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6675
6676/* dynamic buffer ops */
6677DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size);
6678DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
6679
6680#endif /* DUK_HBUFFER_H_INCLUDED */
6681#line 1 "duk_heap.h"
6682/*
6683 * Heap structure.
6684 *
6685 * Heap contains allocated heap objects, interned strings, and built-in
6686 * strings for one or more threads.
6687 */
6688
6689#ifndef DUK_HEAP_H_INCLUDED
6690#define DUK_HEAP_H_INCLUDED
6691
6692/* alloc function typedefs in duktape.h */
6693
6694/*
6695 * Heap flags
6696 */
6697
6698#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */
6699#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
6700#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */
6701#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */
6702#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */
6703#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */
6704
6705#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
6706#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
6707 (heap)->flags |= (bits); \
6708 } while (0)
6709#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \
6710 (heap)->flags &= ~(bits); \
6711 } while (0)
6712
6713#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
6714#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
6715#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
6716#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
6717#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
6718#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
6719
6720#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
6721#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
6722#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
6723#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
6724#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
6725#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
6726
6727#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
6728#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
6729#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
6730#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
6731#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
6732#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
6733
6734/*
6735 * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
6736 */
6737
6738#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */
6739#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */
6740#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */
6741#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
6742#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */
6743#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */
6744#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */
6745#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */
6746
6747/*
6748 * Mark-and-sweep flags
6749 *
6750 * These are separate from heap level flags now but could be merged.
6751 * The heap structure only contains a 'base mark-and-sweep flags'
6752 * field and the GC caller can impose further flags.
6753 */
6754
6755#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */
6756#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */
6757#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */
6758#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */
6759#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */
6760
6761/*
6762 * Thread switching
6763 *
6764 * To switch heap->curr_thread, use the macro below so that interrupt counters
6765 * get updated correctly. The macro allows a NULL target thread because that
6766 * happens e.g. in call handling.
6767 */
6768
6769#if defined(DUK_USE_INTERRUPT_COUNTER)
6770#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr))
6771#else
6772#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \
6773 (heap)->curr_thread = (newthr); \
6774 } while (0)
6775#endif
6776
6777/*
6778 * Other heap related defines
6779 */
6780
6781/* Mark-and-sweep interval is relative to combined count of objects and
6782 * strings kept in the heap during the latest mark-and-sweep pass.
6783 * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is
6784 * decreased by each (re)allocation attempt (regardless of size), and each
6785 * refzero processed object.
6786 *
6787 * 'SKIP' indicates how many (re)allocations to wait until a retry if
6788 * GC is skipped because there is no thread do it with yet (happens
6789 * only during init phases).
6790 */
6791#if defined(DUK_USE_MARK_AND_SWEEP)
6792#if defined(DUK_USE_REFERENCE_COUNTING)
6793#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
6794#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
6795#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
6796#else
6797#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */
6798#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
6799#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
6800#endif
6801#endif
6802
6803/* Stringcache is used for speeding up char-offset-to-byte-offset
6804 * translations for non-ASCII strings.
6805 */
6806#define DUK_HEAP_STRCACHE_SIZE 4
6807#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
6808
6809/* helper to insert a (non-string) heap object into heap allocated list */
6810#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr))
6811
6812/*
6813 * Stringtable
6814 */
6815
6816/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */
6817#define DUK_STRTAB_INITIAL_SIZE 17
6818
6819/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */
6820#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap)
6821
6822/* resizing parameters */
6823#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */
6824#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */
6825#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */
6826
6827#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
6828#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL
6829
6830/* probe sequence (open addressing) */
6831#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
6832#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
6833
6834/* fixed top level hashtable size (separate chaining) */
6835#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE
6836
6837/*
6838 * Built-in strings
6839 */
6840
6841/* heap string indices are autogenerated in duk_strings.h */
6842#if defined(DUK_USE_ROM_STRINGS)
6843#define DUK_HEAP_GET_STRING(heap,idx) \
6844 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
6845#else /* DUK_USE_ROM_STRINGS */
6846#if defined(DUK_USE_HEAPPTR16)
6847#define DUK_HEAP_GET_STRING(heap,idx) \
6848 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)]))
6849#else
6850#define DUK_HEAP_GET_STRING(heap,idx) \
6851 ((heap)->strs[(idx)])
6852#endif
6853#endif /* DUK_USE_ROM_STRINGS */
6854
6855/*
6856 * Raw memory calls: relative to heap, but no GC interaction
6857 */
6858
6859#define DUK_ALLOC_RAW(heap,size) \
6860 ((heap)->alloc_func((heap)->heap_udata, (size)))
6861
6862#define DUK_REALLOC_RAW(heap,ptr,newsize) \
6863 ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize)))
6864
6865#define DUK_FREE_RAW(heap,ptr) \
6866 ((heap)->free_func((heap)->heap_udata, (void *) (ptr)))
6867
6868/*
6869 * Memory calls: relative to heap, GC interaction, but no error throwing.
6870 *
6871 * XXX: Currently a mark-and-sweep triggered by memory allocation will run
6872 * using the heap->heap_thread. This thread is also used for running
6873 * mark-and-sweep finalization; this is not ideal because it breaks the
6874 * isolation between multiple global environments.
6875 *
6876 * Notes:
6877 *
6878 * - DUK_FREE() is required to ignore NULL and any other possible return
6879 * value of a zero-sized alloc/realloc (same as ANSI C free()).
6880 *
6881 * - There is no DUK_REALLOC_ZEROED because we don't assume to know the
6882 * old size. Caller must zero the reallocated memory.
6883 *
6884 * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
6885 * by an allocation failure might invalidate the original 'ptr', thus
6886 * causing a realloc retry to use an invalid pointer. Example: we're
6887 * reallocating the value stack and a finalizer resizes the same value
6888 * stack during mark-and-sweep. The indirect variant requests for the
6889 * current location of the pointer being reallocated using a callback
6890 * right before every realloc attempt; this circuitous approach is used
6891 * to avoid strict aliasing issues in a more straightforward indirect
6892 * pointer (void **) approach. Note: the pointer in the storage
6893 * location is read but is NOT updated; the caller must do that.
6894 */
6895
6896/* callback for indirect reallocs, request for current pointer */
6897typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
6898
6899#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size))
6900#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size))
6901#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize))
6902#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
6903#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
6904
6905/*
6906 * Memory constants
6907 */
6908
6909#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this
6910 * many times. A single mark-and-sweep round is
6911 * not guaranteed to free all unreferenced memory
6912 * because of finalization (in fact, ANY number of
6913 * rounds is strictly not enough).
6914 */
6915
6916#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode
6917 * for mark-and-sweep.
6918 */
6919
6920/*
6921 * Debugger support
6922 */
6923
6924/* Maximum number of breakpoints. Only breakpoints that are set are
6925 * consulted so increasing this has no performance impact.
6926 */
6927#define DUK_HEAP_MAX_BREAKPOINTS 16
6928
6929/* Opcode interval for a Date-based status/peek rate limit check. Only
6930 * relevant when debugger is attached. Requesting a timestamp may be a
6931 * slow operation on some platforms so this shouldn't be too low. On the
6932 * other hand a high value makes Duktape react to a pause request slowly.
6933 */
6934#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000
6935
6936/* Milliseconds between status notify and transport peeks. */
6937#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
6938
6939/* Step types */
6940#define DUK_STEP_TYPE_NONE 0
6941#define DUK_STEP_TYPE_INTO 1
6942#define DUK_STEP_TYPE_OVER 2
6943#define DUK_STEP_TYPE_OUT 3
6944
6945struct duk_breakpoint {
6946 duk_hstring *filename;
6947 duk_uint32_t line;
6948};
6949
6950#if defined(DUK_USE_DEBUGGER_SUPPORT)
6951#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL)
6952#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \
6953 (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \
6954 (heap)->dbg_step_thread = NULL; \
6955 (heap)->dbg_step_csindex = 0; \
6956 (heap)->dbg_step_startline = 0; \
6957 } while (0)
6958#define DUK_HEAP_SET_PAUSED(heap) do { \
6959 (heap)->dbg_paused = 1; \
6960 (heap)->dbg_state_dirty = 1; \
6961 DUK_HEAP_CLEAR_STEP_STATE((heap)); \
6962 } while (0)
6963#define DUK_HEAP_CLEAR_PAUSED(heap) do { \
6964 (heap)->dbg_paused = 0; \
6965 (heap)->dbg_state_dirty = 1; \
6966 DUK_HEAP_CLEAR_STEP_STATE((heap)); \
6967 } while (0)
6968#define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused)
6969#endif /* DUK_USE_DEBUGGER_SUPPORT */
6970
6971/*
6972 * String cache should ideally be at duk_hthread level, but that would
6973 * cause string finalization to slow down relative to the number of
6974 * threads; string finalization must check the string cache for "weak"
6975 * references to the string being finalized to avoid dead pointers.
6976 *
6977 * Thus, string caches are now at the heap level now.
6978 */
6979
6980struct duk_strcache {
6981 duk_hstring *h;
6982 duk_uint32_t bidx;
6983 duk_uint32_t cidx;
6984};
6985
6986/*
6987 * Longjmp state, contains the information needed to perform a longjmp.
6988 * Longjmp related values are written to value1, value2, and iserror.
6989 */
6990
6991struct duk_ljstate {
6992 duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
6993 duk_small_uint_t type; /* longjmp type */
6994 duk_bool_t iserror; /* isError flag for yield */
6995 duk_tval value1; /* 1st related value (type specific) */
6996 duk_tval value2; /* 2nd related value (type specific) */
6997};
6998
6999/*
7000 * Stringtable entry for fixed size stringtable
7001 */
7002
7003struct duk_strtab_entry {
7004#if defined(DUK_USE_HEAPPTR16)
7005 /* A 16-bit listlen makes sense with 16-bit heap pointers: there
7006 * won't be space for 64k strings anyway.
7007 */
7008 duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */
7009 union {
7010 duk_uint16_t strlist16;
7011 duk_uint16_t str16;
7012 } u;
7013#else
7014 duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */
7015 union {
7016 duk_hstring **strlist;
7017 duk_hstring *str;
7018 } u;
7019#endif
7020};
7021
7022/*
7023 * Main heap structure
7024 */
7025
7026struct duk_heap {
7027 duk_small_uint_t flags;
7028
7029 /* Allocator functions. */
7030 duk_alloc_function alloc_func;
7031 duk_realloc_function realloc_func;
7032 duk_free_function free_func;
7033
7034 /* Heap udata, used for allocator functions but also for other heap
7035 * level callbacks like pointer compression, etc.
7036 */
7037 void *heap_udata;
7038
7039 /* Precomputed pointers when using 16-bit heap pointer packing. */
7040#if defined(DUK_USE_HEAPPTR16)
7041 duk_uint16_t heapptr_null16;
7042 duk_uint16_t heapptr_deleted16;
7043#endif
7044
7045 /* Fatal error handling, called e.g. when a longjmp() is needed but
7046 * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
7047 * declared as "noreturn" because doing that for typedefs is a bit
7048 * challenging portability-wise.
7049 */
7050 duk_fatal_function fatal_func;
7051
7052 /* allocated heap objects */
7053 duk_heaphdr *heap_allocated;
7054
7055 /* work list for objects whose refcounts are zero but which have not been
7056 * "finalized"; avoids recursive C calls when refcounts go to zero in a
7057 * chain of objects.
7058 */
7059#if defined(DUK_USE_REFERENCE_COUNTING)
7060 duk_heaphdr *refzero_list;
7061 duk_heaphdr *refzero_list_tail;
7062#endif
7063
7064#if defined(DUK_USE_MARK_AND_SWEEP)
7065 /* mark-and-sweep control */
7066#if defined(DUK_USE_VOLUNTARY_GC)
7067 duk_int_t mark_and_sweep_trigger_counter;
7068#endif
7069 duk_int_t mark_and_sweep_recursion_depth;
7070
7071 /* mark-and-sweep flags automatically active (used for critical sections) */
7072 duk_small_uint_t mark_and_sweep_base_flags;
7073
7074 /* work list for objects to be finalized (by mark-and-sweep) */
7075 duk_heaphdr *finalize_list;
7076#endif
7077
7078 /* longjmp state */
7079 duk_ljstate lj;
7080
7081 /* marker for detecting internal "double faults", see duk_error_throw.c */
7082 duk_bool_t handling_error;
7083
7084 /* heap thread, used internally and for finalization */
7085 duk_hthread *heap_thread;
7086
7087 /* current thread */
7088 duk_hthread *curr_thread; /* currently running thread */
7089
7090 /* heap level "stash" object (e.g., various reachability roots) */
7091 duk_hobject *heap_object;
7092
7093 /* duk_handle_call / duk_handle_safe_call recursion depth limiting */
7094 duk_int_t call_recursion_depth;
7095 duk_int_t call_recursion_limit;
7096
7097 /* mix-in value for computing string hashes; should be reasonably unpredictable */
7098 duk_uint32_t hash_seed;
7099
7100 /* rnd_state for duk_util_tinyrandom.c */
7101 duk_uint32_t rnd_state;
7102
7103 /* For manual debugging: instruction count based on executor and
7104 * interrupt counter book-keeping. Inspect debug logs to see how
7105 * they match up.
7106 */
7107#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
7108 duk_int_t inst_count_exec;
7109 duk_int_t inst_count_interrupt;
7110#endif
7111
7112 /* debugger */
7113
7114#if defined(DUK_USE_DEBUGGER_SUPPORT)
7115 /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */
7116 duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
7117 duk_debug_write_function dbg_write_cb; /* required */
7118 duk_debug_peek_function dbg_peek_cb;
7119 duk_debug_read_flush_function dbg_read_flush_cb;
7120 duk_debug_write_flush_function dbg_write_flush_cb;
7121 duk_debug_request_function dbg_request_cb;
7122 duk_debug_detached_function dbg_detached_cb;
7123 void *dbg_udata;
7124
7125 /* debugger state, only relevant when attached */
7126 duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
7127 duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */
7128 duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
7129 duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
7130 duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
7131 duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */
7132 duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */
7133 duk_size_t dbg_step_csindex; /* callstack index */
7134 duk_uint32_t dbg_step_startline; /* starting line number */
7135 duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
7136 duk_small_uint_t dbg_breakpoint_count;
7137 duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
7138 /* XXX: make active breakpoints actual copies instead of pointers? */
7139
7140 /* These are for rate limiting Status notifications and transport peeking. */
7141 duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
7142 duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
7143 duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
7144
7145 /* Used to support single-byte stream lookahead. */
7146 duk_bool_t dbg_have_next_byte;
7147 duk_uint8_t dbg_next_byte;
7148#endif
7149
7150 /* string intern table (weak refs) */
7151#if defined(DUK_USE_STRTAB_PROBE)
7152#if defined(DUK_USE_HEAPPTR16)
7153 duk_uint16_t *strtable16;
7154#else
7155 duk_hstring **strtable;
7156#endif
7157 duk_uint32_t st_size; /* alloc size in elements */
7158 duk_uint32_t st_used; /* used elements (includes DELETED) */
7159#endif
7160
7161 /* XXX: static alloc is OK until separate chaining stringtable
7162 * resizing is implemented.
7163 */
7164#if defined(DUK_USE_STRTAB_CHAIN)
7165 duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE];
7166#endif
7167
7168 /* string access cache (codepoint offset -> byte offset) for fast string
7169 * character looping; 'weak' reference which needs special handling in GC.
7170 */
7171 duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
7172
7173 /* built-in strings */
7174#if defined(DUK_USE_ROM_STRINGS)
7175 /* No field needed when strings are in ROM. */
7176#else
7177#if defined(DUK_USE_HEAPPTR16)
7178 duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS];
7179#else
7180 duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
7181#endif
7182#endif
7183};
7184
7185/*
7186 * Prototypes
7187 */
7188
7189DUK_INTERNAL_DECL
7190duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
7191 duk_realloc_function realloc_func,
7192 duk_free_function free_func,
7193 void *heap_udata,
7194 duk_fatal_function fatal_func);
7195DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
7196DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h);
7197DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h);
7198DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h);
7199DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
7200
7201DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
7202#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
7203DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
7204#endif
7205#if defined(DUK_USE_INTERRUPT_COUNTER)
7206DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
7207#endif
7208
7209#if 0 /*unused*/
7210DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
7211#endif
7212DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
7213DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
7214#if 0 /*unused*/
7215DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val);
7216#endif
7217DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val);
7218DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
7219#if defined(DUK_USE_REFERENCE_COUNTING)
7220DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h);
7221#endif
7222#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
7223DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap);
7224#endif
7225DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap);
7226#if defined(DUK_USE_DEBUG)
7227DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap);
7228#endif
7229
7230
7231DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
7232DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
7233
7234#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
7235DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size);
7236DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize);
7237DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
7238#endif
7239
7240DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
7241DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
7242DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
7243DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
7244DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
7245
7246#ifdef DUK_USE_REFERENCE_COUNTING
7247#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
7248DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
7249#endif
7250#if 0 /* unused */
7251DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv);
7252#endif
7253DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
7254#if 0 /* unused */
7255DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv);
7256#endif
7257#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
7258DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
7259#endif
7260#if 0 /* unused */
7261DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h);
7262#endif
7263DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
7264DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h);
7265DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
7266DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr);
7267#else
7268/* no refcounting */
7269#endif
7270
7271#if defined(DUK_USE_MARK_AND_SWEEP)
7272DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
7273#endif
7274
7275DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
7276
7277#endif /* DUK_HEAP_H_INCLUDED */
7278#line 1 "duk_debugger.h"
7279#ifndef DUK_DEBUGGER_H_INCLUDED
7280#define DUK_DEBUGGER_H_INCLUDED
7281
7282/* Debugger protocol version is defined in the public API header. */
7283
7284/* Initial bytes for markers. */
7285#define DUK_DBG_IB_EOM 0x00
7286#define DUK_DBG_IB_REQUEST 0x01
7287#define DUK_DBG_IB_REPLY 0x02
7288#define DUK_DBG_IB_ERROR 0x03
7289#define DUK_DBG_IB_NOTIFY 0x04
7290
7291/* Other initial bytes. */
7292#define DUK_DBG_IB_INT4 0x10
7293#define DUK_DBG_IB_STR4 0x11
7294#define DUK_DBG_IB_STR2 0x12
7295#define DUK_DBG_IB_BUF4 0x13
7296#define DUK_DBG_IB_BUF2 0x14
7297#define DUK_DBG_IB_UNUSED 0x15
7298#define DUK_DBG_IB_UNDEFINED 0x16
7299#define DUK_DBG_IB_NULL 0x17
7300#define DUK_DBG_IB_TRUE 0x18
7301#define DUK_DBG_IB_FALSE 0x19
7302#define DUK_DBG_IB_NUMBER 0x1a
7303#define DUK_DBG_IB_OBJECT 0x1b
7304#define DUK_DBG_IB_POINTER 0x1c
7305#define DUK_DBG_IB_LIGHTFUNC 0x1d
7306#define DUK_DBG_IB_HEAPPTR 0x1e
7307/* The short string/integer initial bytes starting from 0x60 don't have
7308 * defines now.
7309 */
7310
7311/* Error codes. */
7312#define DUK_DBG_ERR_UNKNOWN 0x00
7313#define DUK_DBG_ERR_UNSUPPORTED 0x01
7314#define DUK_DBG_ERR_TOOMANY 0x02
7315#define DUK_DBG_ERR_NOTFOUND 0x03
7316#define DUK_DBG_ERR_APPLICATION 0x04
7317
7318/* Commands and notifys initiated by Duktape. */
7319#define DUK_DBG_CMD_STATUS 0x01
7320#define DUK_DBG_CMD_PRINT 0x02
7321#define DUK_DBG_CMD_ALERT 0x03
7322#define DUK_DBG_CMD_LOG 0x04
7323#define DUK_DBG_CMD_THROW 0x05
7324#define DUK_DBG_CMD_DETACHING 0x06
7325#define DUK_DBG_CMD_APPNOTIFY 0x07
7326
7327/* Commands initiated by debug client. */
7328#define DUK_DBG_CMD_BASICINFO 0x10
7329#define DUK_DBG_CMD_TRIGGERSTATUS 0x11
7330#define DUK_DBG_CMD_PAUSE 0x12
7331#define DUK_DBG_CMD_RESUME 0x13
7332#define DUK_DBG_CMD_STEPINTO 0x14
7333#define DUK_DBG_CMD_STEPOVER 0x15
7334#define DUK_DBG_CMD_STEPOUT 0x16
7335#define DUK_DBG_CMD_LISTBREAK 0x17
7336#define DUK_DBG_CMD_ADDBREAK 0x18
7337#define DUK_DBG_CMD_DELBREAK 0x19
7338#define DUK_DBG_CMD_GETVAR 0x1a
7339#define DUK_DBG_CMD_PUTVAR 0x1b
7340#define DUK_DBG_CMD_GETCALLSTACK 0x1c
7341#define DUK_DBG_CMD_GETLOCALS 0x1d
7342#define DUK_DBG_CMD_EVAL 0x1e
7343#define DUK_DBG_CMD_DETACH 0x1f
7344#define DUK_DBG_CMD_DUMPHEAP 0x20
7345#define DUK_DBG_CMD_GETBYTECODE 0x21
7346#define DUK_DBG_CMD_APPREQUEST 0x22
7347#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23
7348#define DUK_DBG_CMD_GETOBJPROPDESC 0x24
7349#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25
7350
7351/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
7352 * The remaining flags are specific to the debugger.
7353 */
7354#define DUK_DBG_PROPFLAG_INTERNAL (1 << 8)
7355
7356#if defined(DUK_USE_DEBUGGER_SUPPORT)
7357DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
7358
7359DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr);
7360DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr);
7361
7362DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length);
7363DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr);
7364
7365DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length);
7366DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr);
7367DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr);
7368DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr);
7369/* XXX: exposed duk_debug_read_pointer */
7370/* XXX: exposed duk_debug_read_buffer */
7371/* XXX: exposed duk_debug_read_hbuffer */
7372#if 0
7373DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr);
7374#endif
7375#if defined(DUK_USE_DEBUGGER_INSPECT)
7376DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr);
7377#endif
7378DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr);
7379
7380DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
7381DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
7382DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
7383DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
7384#if defined(DUK_USE_DEBUGGER_INSPECT)
7385DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr);
7386#endif
7387DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val);
7388DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
7389DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
7390DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
7391DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data);
7392DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
7393DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
7394DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
7395DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
7396#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
7397DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
7398#endif
7399DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
7400DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
7401#if 0 /* unused */
7402DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command);
7403#endif
7404DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr);
7405DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg);
7406DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
7407DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
7408
7409DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
7410DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
7411#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
7412DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
7413#endif
7414
7415DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
7416DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
7417
7418DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
7419DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
7420#endif
7421
7422#endif /* DUK_DEBUGGER_H_INCLUDED */
7423#line 1 "duk_debug.h"
7424/*
7425 * Debugging macros, DUK_DPRINT() and its variants in particular.
7426 *
7427 * DUK_DPRINT() allows formatted debug prints, and supports standard
7428 * and Duktape specific formatters. See duk_debug_vsnprintf.c for details.
7429 *
7430 * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
7431 * for technical reasons. They are concretely used to hide 'x' from the
7432 * compiler when the corresponding log level is disabled. This allows
7433 * clean builds on non-C99 compilers, at the cost of more verbose code.
7434 * Examples:
7435 *
7436 * DUK_D(DUK_DPRINT("foo"));
7437 * DUK_DD(DUK_DDPRINT("foo"));
7438 * DUK_DDD(DUK_DDDPRINT("foo"));
7439 *
7440 * This approach is preferable to the old "double parentheses" hack because
7441 * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
7442 * no longer be added transparently without going through globals, which
7443 * works poorly with threading.
7444 */
7445
7446#ifndef DUK_DEBUG_H_INCLUDED
7447#define DUK_DEBUG_H_INCLUDED
7448
7449#ifdef DUK_USE_DEBUG
7450
7451#if defined(DUK_USE_DPRINT)
7452#define DUK_D(x) x
7453#else
7454#define DUK_D(x) do { } while (0) /* omit */
7455#endif
7456
7457#if defined(DUK_USE_DDPRINT)
7458#define DUK_DD(x) x
7459#else
7460#define DUK_DD(x) do { } while (0) /* omit */
7461#endif
7462
7463#if defined(DUK_USE_DDDPRINT)
7464#define DUK_DDD(x) x
7465#else
7466#define DUK_DDD(x) do { } while (0) /* omit */
7467#endif
7468
7469/*
7470 * Exposed debug macros: debugging enabled
7471 */
7472
7473#define DUK_LEVEL_DEBUG 1
7474#define DUK_LEVEL_DDEBUG 2
7475#define DUK_LEVEL_DDDEBUG 3
7476
7477#ifdef DUK_USE_VARIADIC_MACROS
7478
7479/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
7480 * possible compile time, but waste some space with shared function names.
7481 */
7482#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__);
7483
7484#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
7485
7486#ifdef DUK_USE_DDPRINT
7487#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
7488#else
7489#define DUK_DDPRINT(...)
7490#endif
7491
7492#ifdef DUK_USE_DDDPRINT
7493#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
7494#else
7495#define DUK_DDDPRINT(...)
7496#endif
7497
7498#else /* DUK_USE_VARIADIC_MACROS */
7499
7500#define DUK__DEBUG_STASH(lev) \
7501 (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
7502 duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
7503 (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \
7504 duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
7505 (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
7506 duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
7507 (void) (duk_debug_level_stash = (lev))
7508
7509/* Without variadic macros resort to comma expression trickery to handle debug
7510 * prints. This generates a lot of harmless warnings. These hacks are not
7511 * needed normally because DUK_D() and friends will hide the entire debug log
7512 * statement from the compiler.
7513 */
7514
7515#ifdef DUK_USE_DPRINT
7516#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
7517#else
7518#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
7519#endif
7520
7521#ifdef DUK_USE_DDPRINT
7522#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
7523#else
7524#define DUK_DDPRINT 0 && /* args */
7525#endif
7526
7527#ifdef DUK_USE_DDDPRINT
7528#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
7529#else
7530#define DUK_DDDPRINT 0 && /* args */
7531#endif
7532
7533#endif /* DUK_USE_VARIADIC_MACROS */
7534
7535#else /* DUK_USE_DEBUG */
7536
7537/*
7538 * Exposed debug macros: debugging disabled
7539 */
7540
7541#define DUK_D(x) do { } while (0) /* omit */
7542#define DUK_DD(x) do { } while (0) /* omit */
7543#define DUK_DDD(x) do { } while (0) /* omit */
7544
7545#ifdef DUK_USE_VARIADIC_MACROS
7546
7547#define DUK_DPRINT(...)
7548#define DUK_DDPRINT(...)
7549#define DUK_DDDPRINT(...)
7550
7551#else /* DUK_USE_VARIADIC_MACROS */
7552
7553#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
7554#define DUK_DDPRINT 0 && /* args */
7555#define DUK_DDDPRINT 0 && /* args */
7556
7557#endif /* DUK_USE_VARIADIC_MACROS */
7558
7559#endif /* DUK_USE_DEBUG */
7560
7561/*
7562 * Structs
7563 */
7564
7565#ifdef DUK_USE_DEBUG
7566struct duk_fixedbuffer {
7567 duk_uint8_t *buffer;
7568 duk_size_t length;
7569 duk_size_t offset;
7570 duk_bool_t truncated;
7571};
7572#endif
7573
7574/*
7575 * Prototypes
7576 */
7577
7578#ifdef DUK_USE_DEBUG
7579DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
7580#if 0 /*unused*/
7581DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
7582#endif
7583DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
7584
7585#ifdef DUK_USE_VARIADIC_MACROS
7586DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
7587#else /* DUK_USE_VARIADIC_MACROS */
7588/* parameter passing, not thread safe */
7589#define DUK_DEBUG_STASH_SIZE 128
7590#if !defined(DUK_SINGLE_FILE)
7591DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
7592DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
7593DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
7594DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash;
7595#endif
7596DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
7597#endif /* DUK_USE_VARIADIC_MACROS */
7598
7599DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
7600DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
7601DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
7602DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
7603DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
7604DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
7605
7606#endif /* DUK_USE_DEBUG */
7607
7608#endif /* DUK_DEBUG_H_INCLUDED */
7609#line 1 "duk_error.h"
7610/*
7611 * Error handling macros, assertion macro, error codes.
7612 *
7613 * There are three level of 'errors':
7614 *
7615 * 1. Ordinary errors, relative to a thread, cause a longjmp, catchable.
7616 * 2. Fatal errors, relative to a heap, cause fatal handler to be called.
7617 * 3. Panic errors, unrelated to a heap and cause a process exit.
7618 *
7619 * Panics are used by the default fatal error handler and by debug code
7620 * such as assertions. By providing a proper fatal error handler, user
7621 * code can avoid panics in non-debug builds.
7622 */
7623
7624#ifndef DUK_ERROR_H_INCLUDED
7625#define DUK_ERROR_H_INCLUDED
7626
7627/*
7628 * Error codes: defined in duktape.h
7629 *
7630 * Error codes are used as a shorthand to throw exceptions from inside
7631 * the implementation. The appropriate Ecmascript object is constructed
7632 * based on the code. Ecmascript code throws objects directly. The error
7633 * codes are defined in the public API header because they are also used
7634 * by calling code.
7635 */
7636
7637/*
7638 * Normal error
7639 *
7640 * Normal error is thrown with a longjmp() through the current setjmp()
7641 * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap
7642 * identifies the throwing thread.
7643 *
7644 * Error formatting is usually unnecessary. The error macros provide a
7645 * zero argument version (no formatting) and separate macros for small
7646 * argument counts. Variadic macros are not used to avoid portability
7647 * issues and avoid the need for stash-based workarounds when they're not
7648 * available. Vararg calls are avoided for non-formatted error calls
7649 * because vararg call sites are larger than normal, and there are a lot
7650 * of call sites with no formatting.
7651 *
7652 * Note that special formatting provided by debug macros is NOT available.
7653 *
7654 * The _RAW variants allow the caller to specify file and line. This makes
7655 * it easier to write checked calls which want to use the call site of the
7656 * checked function, not the error macro call inside the checked function.
7657 */
7658
7659#if defined(DUK_USE_VERBOSE_ERRORS)
7660
7661/* Because there are quite many call sites, pack error code (require at most
7662 * 8-bit) into a single argument.
7663 */
7664#define DUK_ERROR(thr,err,msg) do { \
7665 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7666 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7667 duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
7668 } while (0)
7669#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \
7670 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7671 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7672 duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
7673 } while (0)
7674
7675#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \
7676 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7677 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7678 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
7679 } while (0)
7680#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \
7681 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7682 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7683 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
7684 } while (0)
7685
7686#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \
7687 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7688 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7689 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
7690 } while (0)
7691#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \
7692 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7693 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7694 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
7695 } while (0)
7696
7697#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \
7698 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7699 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7700 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
7701 } while (0)
7702#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \
7703 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7704 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7705 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
7706 } while (0)
7707
7708#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \
7709 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7710 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7711 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)); \
7712 } while (0)
7713#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \
7714 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7715 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7716 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
7717 } while (0)
7718
7719#else /* DUK_USE_VERBOSE_ERRORS */
7720
7721#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err))
7722#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err))
7723
7724#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt))
7725#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7726
7727#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt))
7728#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7729
7730#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt))
7731#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7732
7733#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt))
7734#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7735
7736#endif /* DUK_USE_VERBOSE_ERRORS */
7737
7738/*
7739 * Fatal error
7740 *
7741 * There are no fatal error macros at the moment. There are so few call
7742 * sites that the fatal error handler is called directly.
7743 */
7744
7745/*
7746 * Panic error
7747 *
7748 * Panic errors are not relative to either a heap or a thread, and cause
7749 * DUK_PANIC() macro to be invoked. Unless a user provides DUK_USE_PANIC_HANDLER,
7750 * DUK_PANIC() calls a helper which prints out the error and causes a process
7751 * exit.
7752 *
7753 * The user can override the macro to provide custom handling. A macro is
7754 * used to allow the user to have inline panic handling if desired (without
7755 * causing a potentially risky function call).
7756 *
7757 * Panics are only used in debug code such as assertions, and by the default
7758 * fatal error handler.
7759 */
7760
7761#if defined(DUK_USE_PANIC_HANDLER)
7762/* already defined, good */
7763#define DUK_PANIC(code,msg) DUK_USE_PANIC_HANDLER((code),(msg))
7764#else
7765#define DUK_PANIC(code,msg) duk_default_panic_handler((code),(msg))
7766#endif /* DUK_USE_PANIC_HANDLER */
7767
7768/*
7769 * Assert macro: failure causes panic.
7770 */
7771
7772#if defined(DUK_USE_ASSERTIONS)
7773
7774/* the message should be a compile time constant without formatting (less risk);
7775 * we don't care about assertion text size because they're not used in production
7776 * builds.
7777 */
7778#define DUK_ASSERT(x) do { \
7779 if (!(x)) { \
7780 DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
7781 "assertion failed: " #x \
7782 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
7783 } \
7784 } while (0)
7785
7786/* Assertion compatible inside a comma expression, evaluates to void.
7787 * Currently not compatible with DUK_USE_PANIC_HANDLER() which may have
7788 * a statement block.
7789 */
7790#if defined(DUK_USE_PANIC_HANDLER)
7791/* XXX: resolve macro definition issue or call through a helper function? */
7792#define DUK_ASSERT_EXPR(x) ((void) 0)
7793#else
7794#define DUK_ASSERT_EXPR(x) \
7795 ((void) ((x) ? 0 : (DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
7796 "assertion failed: " #x \
7797 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
7798#endif
7799
7800#else /* DUK_USE_ASSERTIONS */
7801
7802#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0)
7803
7804#define DUK_ASSERT_EXPR(x) ((void) 0)
7805
7806#endif /* DUK_USE_ASSERTIONS */
7807
7808/* this variant is used when an assert would generate a compile warning by
7809 * being always true (e.g. >= 0 comparison for an unsigned value
7810 */
7811#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0)
7812
7813/*
7814 * Assertion helpers
7815 */
7816
7817#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
7818#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \
7819 DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
7820 } while (0)
7821#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \
7822 if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
7823 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
7824 } \
7825 } while (0)
7826#else
7827#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */
7828#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */
7829#endif
7830
7831#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n))
7832
7833#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
7834#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \
7835 duk_double_union duk__assert_tmp_du; \
7836 duk__assert_tmp_du.d = (dval); \
7837 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \
7838 } while (0)
7839#else
7840#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
7841#endif
7842
7843/*
7844 * Helper for valstack space
7845 *
7846 * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
7847 * required for its own use, and any child calls which are not (a) Duktape API calls
7848 * or (b) Duktape calls which involve extending the valstack (e.g. getter call).
7849 */
7850
7851#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape
7852 * API calls in addition to function's own use
7853 */
7854#if defined(DUK_USE_ASSERTIONS)
7855#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \
7856 DUK_ASSERT((thr) != NULL); \
7857 DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
7858 } while (0)
7859#else
7860#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */
7861#endif
7862
7863/*
7864 * Error throwing helpers
7865 *
7866 * The goal is to provide verbose and configurable error messages. Call
7867 * sites should be clean in source code and compile to a small footprint.
7868 * Small footprint is also useful for performance because small cold paths
7869 * reduce code cache pressure. Adding macros here only makes sense if there
7870 * are enough call sites to get concrete benefits.
7871 */
7872
7873#if defined(DUK_USE_VERBOSE_ERRORS)
7874/* Verbose errors with key/value summaries (non-paranoid) or without key/value
7875 * summaries (paranoid, for some security sensitive environments), the paranoid
7876 * vs. non-paranoid distinction affects only a few specific errors.
7877 */
7878#if defined(DUK_USE_PARANOID_ERRORS)
7879#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
7880 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
7881 } while (0)
7882#else /* DUK_USE_PARANOID_ERRORS */
7883#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
7884 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
7885 } while (0)
7886#endif /* DUK_USE_PARANOID_ERRORS */
7887
7888#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
7889 DUK_ERROR((thr), DUK_ERR_UNIMPLEMENTED_ERROR, (msg)); \
7890 } while (0)
7891#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
7892 duk_err_unimplemented_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
7893 } while (0)
7894#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
7895 DUK_ERROR((thr), DUK_ERR_UNSUPPORTED_ERROR, (msg)); \
7896 } while (0)
7897#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
7898#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
7899 duk_err_unsupported_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
7900 } while (0)
7901#endif
7902#define DUK_ERROR_INTERNAL(thr,msg) do { \
7903 duk_err_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7904 } while (0)
7905#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
7906 duk_err_internal_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
7907 } while (0)
7908#define DUK_ERROR_ALLOC(thr,msg) do { \
7909 duk_err_alloc((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7910 } while (0)
7911#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
7912 DUK_ERROR_ALLOC((thr), DUK_STR_ALLOC_FAILED); \
7913 } while (0)
7914/* DUK_ERR_ASSERTION_ERROR: no macros needed */
7915#define DUK_ERROR_API_INDEX(thr,index) do { \
7916 duk_err_api_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index)); \
7917 } while (0)
7918#define DUK_ERROR_API(thr,msg) do { \
7919 duk_err_api((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7920 } while (0)
7921/* DUK_ERR_UNCAUGHT_ERROR: no macros needed */
7922/* DUK_ERR_ERROR: no macros needed */
7923/* DUK_ERR_EVAL: no macros needed */
7924#define DUK_ERROR_RANGE(thr,msg) do { \
7925 duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7926 } while (0)
7927/* DUK_ERR_REFERENCE_ERROR: no macros needed */
7928#define DUK_ERROR_SYNTAX(thr,msg) do { \
7929 DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
7930 } while (0)
7931#define DUK_ERROR_TYPE(thr,msg) do { \
7932 DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
7933 } while (0)
7934/* DUK_ERR_URI_ERROR: no macros needed */
7935#else /* DUK_USE_VERBOSE_ERRORS */
7936/* Non-verbose errors for low memory targets: no file, line, or message. */
7937
7938#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
7939 duk_err_type((thr)); \
7940 } while (0)
7941
7942#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
7943 duk_err_unimplemented((thr)); \
7944 } while (0)
7945#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
7946 duk_err_unimplemented((thr)); \
7947 } while (0)
7948#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
7949 duk_err_unsupported((thr)); \
7950 } while (0)
7951#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
7952 duk_err_unsupported((thr)); \
7953 } while (0)
7954#define DUK_ERROR_INTERNAL(thr,msg) do { \
7955 duk_err_internal((thr)); \
7956 } while (0)
7957#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
7958 duk_err_internal((thr)); \
7959 } while (0)
7960#define DUK_ERROR_ALLOC(thr,msg) do { \
7961 duk_err_alloc((thr)); \
7962 } while (0)
7963#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
7964 duk_err_alloc((thr)); \
7965 } while (0)
7966#define DUK_ERROR_API_INDEX(thr,index) do { \
7967 duk_err_api((thr)); \
7968 } while (0)
7969#define DUK_ERROR_API(thr,msg) do { \
7970 duk_err_api((thr)); \
7971 } while (0)
7972#define DUK_ERROR_RANGE(thr,msg) do { \
7973 duk_err_range((thr)); \
7974 } while (0)
7975#define DUK_ERROR_SYNTAX(thr,msg) do { \
7976 duk_err_syntax((thr)); \
7977 } while (0)
7978#define DUK_ERROR_TYPE(thr,msg) do { \
7979 duk_err_type((thr)); \
7980 } while (0)
7981#endif /* DUK_USE_VERBOSE_ERRORS */
7982
7983/*
7984 * Prototypes
7985 */
7986
7987#if defined(DUK_USE_VERBOSE_ERRORS)
7988DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg));
7989DUK_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, ...));
7990#else /* DUK_USE_VERBOSE_ERRORS */
7991DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
7992#endif /* DUK_USE_VERBOSE_ERRORS */
7993
7994#if defined(DUK_USE_VERBOSE_ERRORS)
7995DUK_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));
7996#else
7997DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
7998#endif
7999
8000DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
8001
8002#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
8003DUK_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);
8004#endif
8005#if defined(DUK_USE_AUGMENT_ERROR_THROW)
8006DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
8007#endif
8008
8009#if defined(DUK_USE_VERBOSE_ERRORS)
8010#if defined(DUK_USE_PARANOID_ERRORS)
8011DUK_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));
8012#else
8013DUK_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));
8014#endif
8015DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index));
8016DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
8017DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
8018DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8019#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
8020DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8021#endif
8022DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8023DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
8024DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
8025#else /* DUK_VERBOSE_ERRORS */
8026DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
8027DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
8028DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
8029DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr));
8030DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented(duk_hthread *thr));
8031DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported(duk_hthread *thr));
8032DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr));
8033DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr));
8034#endif /* DUK_VERBOSE_ERRORS */
8035
8036DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
8037
8038DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg));
8039
8040#if !defined(DUK_USE_PANIC_HANDLER)
8041DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_panic_handler(duk_errcode_t code, const char *msg));
8042#endif
8043
8044DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type);
8045
8046DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
8047
8048#endif /* DUK_ERROR_H_INCLUDED */
8049#line 1 "duk_unicode.h"
8050/*
8051 * Unicode helpers
8052 */
8053
8054#ifndef DUK_UNICODE_H_INCLUDED
8055#define DUK_UNICODE_H_INCLUDED
8056
8057/*
8058 * UTF-8 / XUTF-8 / CESU-8 constants
8059 */
8060
8061#define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */
8062#define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
8063#define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */
8064#define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
8065
8066/*
8067 * Useful Unicode codepoints
8068 *
8069 * Integer constants must be signed to avoid unexpected coercions
8070 * in comparisons.
8071 */
8072
8073#define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */
8074#define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */
8075#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */
8076
8077/*
8078 * ASCII character constants
8079 *
8080 * C character literals like 'x' have a platform specific value and do
8081 * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use
8082 * these (admittedly awkward) constants instead. These constants must
8083 * also have signed values to avoid unexpected coercions in comparisons.
8084 *
8085 * http://en.wikipedia.org/wiki/ASCII
8086 */
8087
8088#define DUK_ASC_NUL 0x00
8089#define DUK_ASC_SOH 0x01
8090#define DUK_ASC_STX 0x02
8091#define DUK_ASC_ETX 0x03
8092#define DUK_ASC_EOT 0x04
8093#define DUK_ASC_ENQ 0x05
8094#define DUK_ASC_ACK 0x06
8095#define DUK_ASC_BEL 0x07
8096#define DUK_ASC_BS 0x08
8097#define DUK_ASC_HT 0x09
8098#define DUK_ASC_LF 0x0a
8099#define DUK_ASC_VT 0x0b
8100#define DUK_ASC_FF 0x0c
8101#define DUK_ASC_CR 0x0d
8102#define DUK_ASC_SO 0x0e
8103#define DUK_ASC_SI 0x0f
8104#define DUK_ASC_DLE 0x10
8105#define DUK_ASC_DC1 0x11
8106#define DUK_ASC_DC2 0x12
8107#define DUK_ASC_DC3 0x13
8108#define DUK_ASC_DC4 0x14
8109#define DUK_ASC_NAK 0x15
8110#define DUK_ASC_SYN 0x16
8111#define DUK_ASC_ETB 0x17
8112#define DUK_ASC_CAN 0x18
8113#define DUK_ASC_EM 0x19
8114#define DUK_ASC_SUB 0x1a
8115#define DUK_ASC_ESC 0x1b
8116#define DUK_ASC_FS 0x1c
8117#define DUK_ASC_GS 0x1d
8118#define DUK_ASC_RS 0x1e
8119#define DUK_ASC_US 0x1f
8120#define DUK_ASC_SPACE 0x20
8121#define DUK_ASC_EXCLAMATION 0x21
8122#define DUK_ASC_DOUBLEQUOTE 0x22
8123#define DUK_ASC_HASH 0x23
8124#define DUK_ASC_DOLLAR 0x24
8125#define DUK_ASC_PERCENT 0x25
8126#define DUK_ASC_AMP 0x26
8127#define DUK_ASC_SINGLEQUOTE 0x27
8128#define DUK_ASC_LPAREN 0x28
8129#define DUK_ASC_RPAREN 0x29
8130#define DUK_ASC_STAR 0x2a
8131#define DUK_ASC_PLUS 0x2b
8132#define DUK_ASC_COMMA 0x2c
8133#define DUK_ASC_MINUS 0x2d
8134#define DUK_ASC_PERIOD 0x2e
8135#define DUK_ASC_SLASH 0x2f
8136#define DUK_ASC_0 0x30
8137#define DUK_ASC_1 0x31
8138#define DUK_ASC_2 0x32
8139#define DUK_ASC_3 0x33
8140#define DUK_ASC_4 0x34
8141#define DUK_ASC_5 0x35
8142#define DUK_ASC_6 0x36
8143#define DUK_ASC_7 0x37
8144#define DUK_ASC_8 0x38
8145#define DUK_ASC_9 0x39
8146#define DUK_ASC_COLON 0x3a
8147#define DUK_ASC_SEMICOLON 0x3b
8148#define DUK_ASC_LANGLE 0x3c
8149#define DUK_ASC_EQUALS 0x3d
8150#define DUK_ASC_RANGLE 0x3e
8151#define DUK_ASC_QUESTION 0x3f
8152#define DUK_ASC_ATSIGN 0x40
8153#define DUK_ASC_UC_A 0x41
8154#define DUK_ASC_UC_B 0x42
8155#define DUK_ASC_UC_C 0x43
8156#define DUK_ASC_UC_D 0x44
8157#define DUK_ASC_UC_E 0x45
8158#define DUK_ASC_UC_F 0x46
8159#define DUK_ASC_UC_G 0x47
8160#define DUK_ASC_UC_H 0x48
8161#define DUK_ASC_UC_I 0x49
8162#define DUK_ASC_UC_J 0x4a
8163#define DUK_ASC_UC_K 0x4b
8164#define DUK_ASC_UC_L 0x4c
8165#define DUK_ASC_UC_M 0x4d
8166#define DUK_ASC_UC_N 0x4e
8167#define DUK_ASC_UC_O 0x4f
8168#define DUK_ASC_UC_P 0x50
8169#define DUK_ASC_UC_Q 0x51
8170#define DUK_ASC_UC_R 0x52
8171#define DUK_ASC_UC_S 0x53
8172#define DUK_ASC_UC_T 0x54
8173#define DUK_ASC_UC_U 0x55
8174#define DUK_ASC_UC_V 0x56
8175#define DUK_ASC_UC_W 0x57
8176#define DUK_ASC_UC_X 0x58
8177#define DUK_ASC_UC_Y 0x59
8178#define DUK_ASC_UC_Z 0x5a
8179#define DUK_ASC_LBRACKET 0x5b
8180#define DUK_ASC_BACKSLASH 0x5c
8181#define DUK_ASC_RBRACKET 0x5d
8182#define DUK_ASC_CARET 0x5e
8183#define DUK_ASC_UNDERSCORE 0x5f
8184#define DUK_ASC_GRAVE 0x60
8185#define DUK_ASC_LC_A 0x61
8186#define DUK_ASC_LC_B 0x62
8187#define DUK_ASC_LC_C 0x63
8188#define DUK_ASC_LC_D 0x64
8189#define DUK_ASC_LC_E 0x65
8190#define DUK_ASC_LC_F 0x66
8191#define DUK_ASC_LC_G 0x67
8192#define DUK_ASC_LC_H 0x68
8193#define DUK_ASC_LC_I 0x69
8194#define DUK_ASC_LC_J 0x6a
8195#define DUK_ASC_LC_K 0x6b
8196#define DUK_ASC_LC_L 0x6c
8197#define DUK_ASC_LC_M 0x6d
8198#define DUK_ASC_LC_N 0x6e
8199#define DUK_ASC_LC_O 0x6f
8200#define DUK_ASC_LC_P 0x70
8201#define DUK_ASC_LC_Q 0x71
8202#define DUK_ASC_LC_R 0x72
8203#define DUK_ASC_LC_S 0x73
8204#define DUK_ASC_LC_T 0x74
8205#define DUK_ASC_LC_U 0x75
8206#define DUK_ASC_LC_V 0x76
8207#define DUK_ASC_LC_W 0x77
8208#define DUK_ASC_LC_X 0x78
8209#define DUK_ASC_LC_Y 0x79
8210#define DUK_ASC_LC_Z 0x7a
8211#define DUK_ASC_LCURLY 0x7b
8212#define DUK_ASC_PIPE 0x7c
8213#define DUK_ASC_RCURLY 0x7d
8214#define DUK_ASC_TILDE 0x7e
8215#define DUK_ASC_DEL 0x7f
8216
8217/*
8218 * Unicode tables
8219 */
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_ids_noa[791];
8227#else
8228/*
8229 * Automatically generated by extract_chars.py, do not edit!
8230 */
8231
8232extern const duk_uint8_t duk_unicode_ids_noabmp[611];
8233#endif
8234
8235#ifdef DUK_USE_SOURCE_NONBMP
8236/*
8237 * Automatically generated by extract_chars.py, do not edit!
8238 */
8239
8240extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
8241#else
8242/*
8243 * Automatically generated by extract_chars.py, do not edit!
8244 */
8245
8246extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
8247#endif
8248
8249#ifdef DUK_USE_SOURCE_NONBMP
8250/*
8251 * Automatically generated by extract_chars.py, do not edit!
8252 */
8253
8254extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397];
8255#else
8256/*
8257 * Automatically generated by extract_chars.py, do not edit!
8258 */
8259
8260extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348];
8261#endif
8262
8263/*
8264 * Automatically generated by extract_caseconv.py, do not edit!
8265 */
8266
8267extern const duk_uint8_t duk_unicode_caseconv_uc[1288];
8268extern const duk_uint8_t duk_unicode_caseconv_lc[616];
8269
8270#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
8271/*
8272 * Automatically generated by extract_caseconv.py, do not edit!
8273 */
8274
8275extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
8276#endif
8277
8278/*
8279 * Extern
8280 */
8281
8282/* duk_unicode_support.c */
8283#if !defined(DUK_SINGLE_FILE)
8284DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7];
8285DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2];
8286DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22];
8287DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8];
8288DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4];
8289DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24];
8290DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10];
8291DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128];
8292#endif /* !DUK_SINGLE_FILE */
8293
8294/*
8295 * Prototypes
8296 */
8297
8298DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp);
8299#if defined(DUK_USE_ASSERTIONS)
8300DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp);
8301#endif
8302DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out);
8303DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out);
8304DUK_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);
8305DUK_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);
8306DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen);
8307DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp);
8308DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp);
8309DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp);
8310DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
8311DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
8312DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
8313DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
8314DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
8315
8316#endif /* DUK_UNICODE_H_INCLUDED */
8317#line 1 "duk_json.h"
8318/*
8319 * Defines for JSON, especially duk_bi_json.c.
8320 */
8321
8322#ifndef DUK_JSON_H_INCLUDED
8323#define DUK_JSON_H_INCLUDED
8324
8325/* Encoding/decoding flags */
8326#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */
8327#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */
8328#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */
8329#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */
8330
8331/* How much stack to require on entry to object/array encode */
8332#define DUK_JSON_ENC_REQSTACK 32
8333
8334/* How much stack to require on entry to object/array decode */
8335#define DUK_JSON_DEC_REQSTACK 32
8336
8337/* How large a loop detection stack to use */
8338#define DUK_JSON_ENC_LOOPARRAY 64
8339
8340/* Encoding state. Heap object references are all borrowed. */
8341typedef struct {
8342 duk_hthread *thr;
8343 duk_bufwriter_ctx bw; /* output bufwriter */
8344 duk_hobject *h_replacer; /* replacer function */
8345 duk_hstring *h_gap; /* gap (if empty string, NULL) */
8346 duk_idx_t idx_proplist; /* explicit PropertyList */
8347 duk_idx_t idx_loop; /* valstack index of loop detection object */
8348 duk_small_uint_t flags;
8349 duk_small_uint_t flag_ascii_only;
8350 duk_small_uint_t flag_avoid_key_quotes;
8351#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
8352 duk_small_uint_t flag_ext_custom;
8353 duk_small_uint_t flag_ext_compatible;
8354 duk_small_uint_t flag_ext_custom_or_compatible;
8355#endif
8356 duk_int_t recursion_depth;
8357 duk_int_t recursion_limit;
8358 duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
8359#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
8360 duk_small_uint_t stridx_custom_undefined;
8361 duk_small_uint_t stridx_custom_nan;
8362 duk_small_uint_t stridx_custom_neginf;
8363 duk_small_uint_t stridx_custom_posinf;
8364 duk_small_uint_t stridx_custom_function;
8365#endif
8366 duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */
8367} duk_json_enc_ctx;
8368
8369typedef struct {
8370 duk_hthread *thr;
8371 const duk_uint8_t *p;
8372 const duk_uint8_t *p_start;
8373 const duk_uint8_t *p_end;
8374 duk_idx_t idx_reviver;
8375 duk_small_uint_t flags;
8376#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
8377 duk_small_uint_t flag_ext_custom;
8378 duk_small_uint_t flag_ext_compatible;
8379 duk_small_uint_t flag_ext_custom_or_compatible;
8380#endif
8381 duk_int_t recursion_depth;
8382 duk_int_t recursion_limit;
8383} duk_json_dec_ctx;
8384
8385#endif /* DUK_JSON_H_INCLUDED */
8386#line 1 "duk_js.h"
8387/*
8388 * Ecmascript execution, support primitives.
8389 */
8390
8391#ifndef DUK_JS_H_INCLUDED
8392#define DUK_JS_H_INCLUDED
8393
8394/* Flags for call handling. */
8395#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
8396#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
8397#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
8398#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
8399#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
8400
8401/* Flags for duk_js_equals_helper(). */
8402#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
8403#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */
8404
8405/* Flags for duk_js_compare_helper(). */
8406#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 0) /* eval left argument first */
8407#define DUK_COMPARE_FLAG_NEGATE (1 << 1) /* negate result */
8408
8409/* conversions, coercions, comparison, etc */
8410DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
8411DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv);
8412DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x);
8413DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
8414DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
8415DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
8416DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
8417DUK_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);
8418DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h);
8419DUK_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);
8420DUK_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);
8421DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
8422#if 0 /* unused */
8423DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
8424#endif
8425DUK_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);
8426DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
8427DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
8428DUK_INTERNAL_DECL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x);
8429
8430#define duk_js_equals(thr,tv_x,tv_y) \
8431 duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
8432#define duk_js_strict_equals(tv_x,tv_y) \
8433 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
8434#define duk_js_samevalue(tv_x,tv_y) \
8435 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
8436
8437/* E5 Sections 11.8.1, 11.8.5; x < y */
8438#define duk_js_lessthan(thr,tv_x,tv_y) \
8439 duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
8440
8441/* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */
8442#define duk_js_greaterthan(thr,tv_x,tv_y) \
8443 duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
8444
8445/* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */
8446#define duk_js_lessthanorequal(thr,tv_x,tv_y) \
8447 duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
8448
8449/* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */
8450#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
8451 duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
8452
8453/* identifiers and environment handling */
8454#if 0 /*unused*/
8455DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
8456#endif
8457DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag);
8458DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag);
8459DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict);
8460DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict);
8461#if 0 /*unused*/
8462DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
8463#endif
8464DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
8465DUK_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);
8466DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
8467DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase);
8468DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom);
8469DUK_INTERNAL_DECL
8470void duk_js_push_closure(duk_hthread *thr,
8471 duk_hcompiledfunction *fun_temp,
8472 duk_hobject *outer_var_env,
8473 duk_hobject *outer_lex_env,
8474 duk_bool_t add_auto_proto);
8475
8476/* call handling */
8477DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
8478DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
8479DUK_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);
8480DUK_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);
8481
8482/* bytecode execution */
8483DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
8484
8485#endif /* DUK_JS_H_INCLUDED */
8486#line 1 "duk_numconv.h"
8487#ifndef DUK_NUMCONV_H_INCLUDED
8488#define DUK_NUMCONV_H_INCLUDED
8489
8490/*
8491 * Number-to-string conversion. The semantics of these is very tightly
8492 * bound with the Ecmascript semantics required for call sites.
8493 */
8494
8495/* Output a specified number of digits instead of using the shortest
8496 * form. Used for toPrecision() and toFixed().
8497 */
8498#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0)
8499
8500/* Force exponential format. Used for toExponential(). */
8501#define DUK_N2S_FLAG_FORCE_EXP (1 << 1)
8502
8503/* If number would need zero padding (for whole number part), use
8504 * exponential format instead. E.g. if input number is 12300, 3
8505 * digits are generated ("123"), output "1.23e+4" instead of "12300".
8506 * Used for toPrecision().
8507 */
8508#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2)
8509
8510/* Digit count indicates number of fractions (i.e. an absolute
8511 * digit index instead of a relative one). Used together with
8512 * DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
8513 */
8514#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3)
8515
8516/*
8517 * String-to-number conversion
8518 */
8519
8520/* Maximum exponent value when parsing numbers. This is not strictly
8521 * compliant as there should be no upper limit, but as we parse the
8522 * exponent without a bigint, impose some limit.
8523 */
8524#define DUK_S2N_MAX_EXPONENT 1000000000
8525
8526/* Trim white space (= allow leading and trailing whitespace) */
8527#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0)
8528
8529/* Allow exponent */
8530#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1)
8531
8532/* Allow trailing garbage (e.g. treat "123foo" as "123) */
8533#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2)
8534
8535/* Allow leading plus sign */
8536#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3)
8537
8538/* Allow leading minus sign */
8539#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4)
8540
8541/* Allow 'Infinity' */
8542#define DUK_S2N_FLAG_ALLOW_INF (1 << 5)
8543
8544/* Allow fraction part */
8545#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6)
8546
8547/* Allow naked fraction (e.g. ".123") */
8548#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7)
8549
8550/* Allow empty fraction (e.g. "123.") */
8551#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8)
8552
8553/* Allow empty string to be interpreted as 0 */
8554#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9)
8555
8556/* Allow leading zeroes (e.g. "0123" -> "123") */
8557#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10)
8558
8559/* Allow automatic detection of hex base ("0x" or "0X" prefix),
8560 * overrides radix argument and forces integer mode.
8561 */
8562#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11)
8563
8564/* Allow automatic detection of octal base, overrides radix
8565 * argument and forces integer mode.
8566 */
8567#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 12)
8568
8569/*
8570 * Prototypes
8571 */
8572
8573DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
8574DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
8575
8576#endif /* DUK_NUMCONV_H_INCLUDED */
8577#line 1 "duk_bi_protos.h"
8578/*
8579 * Prototypes for built-in functions not automatically covered by the
8580 * header declarations emitted by genbuiltins.py.
8581 */
8582
8583#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED
8584#define DUK_BUILTIN_PROTOS_H_INCLUDED
8585
8586/* Buffer size needed for duk_bi_date_format_timeval().
8587 * Accurate value is 32 + 1 for NUL termination:
8588 * >>> len('+123456-01-23T12:34:56.123+12:34')
8589 * 32
8590 * Include additional space to be safe.
8591 */
8592#define DUK_BI_DATE_ISO8601_BUFSIZE 48
8593
8594/* Maximum length of CommonJS module identifier to resolve. Length includes
8595 * both current module ID, requested (possibly relative) module ID, and a
8596 * slash in between.
8597 */
8598#define DUK_BI_COMMONJS_MODULE_ID_LIMIT 256
8599
8600/* Helpers exposed for internal use */
8601DUK_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);
8602DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
8603DUK_INTERNAL_DECL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf);
8604DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
8605DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
8606DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
8607DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
8608/* Built-in providers */
8609#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
8610DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx);
8611#endif
8612#if defined(DUK_USE_DATE_NOW_TIME)
8613DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
8614#endif
8615#if defined(DUK_USE_DATE_NOW_WINDOWS)
8616DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
8617#endif
8618#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
8619DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
8620#endif
8621#if defined(DUK_USE_DATE_TZO_WINDOWS)
8622DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
8623#endif
8624#if defined(DUK_USE_DATE_PRS_STRPTIME)
8625DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str);
8626#endif
8627#if defined(DUK_USE_DATE_PRS_GETDATE)
8628DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str);
8629#endif
8630#if defined(DUK_USE_DATE_FMT_STRFTIME)
8631DUK_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);
8632#endif
8633
8634DUK_INTERNAL_DECL
8635void duk_bi_json_parse_helper(duk_context *ctx,
8636 duk_idx_t idx_value,
8637 duk_idx_t idx_reviver,
8638 duk_small_uint_t flags);
8639DUK_INTERNAL_DECL
8640void duk_bi_json_stringify_helper(duk_context *ctx,
8641 duk_idx_t idx_value,
8642 duk_idx_t idx_replacer,
8643 duk_idx_t idx_space,
8644 duk_small_uint_t flags);
8645
8646#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
8647#line 1 "duk_selftest.h"
8648/*
8649 * Selftest code
8650 */
8651
8652#ifndef DUK_SELFTEST_H_INCLUDED
8653#define DUK_SELFTEST_H_INCLUDED
8654
8655#if defined(DUK_USE_SELF_TESTS)
8656DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
8657#endif
8658
8659#endif /* DUK_SELFTEST_H_INCLUDED */
8660#line 78 "duk_internal.h"
8661
8662#endif /* DUK_INTERNAL_H_INCLUDED */
8663#line 1 "duk_replacements.c"
8664/*
8665 * Replacements for missing platform functions.
8666 *
8667 * Unlike the originals, fpclassify() and signbit() replacements don't
8668 * work on any floating point types, only doubles. The C typing here
8669 * mimics the standard prototypes.
8670 */
8671
8672/* include removed: duk_internal.h */
8673
8674#if defined(DUK_USE_COMPUTED_NAN)
8675DUK_INTERNAL double duk_computed_nan;
8676#endif
8677
8678#if defined(DUK_USE_COMPUTED_INFINITY)
8679DUK_INTERNAL double duk_computed_infinity;
8680#endif
8681
8682#if defined(DUK_USE_REPL_FPCLASSIFY)
8683DUK_INTERNAL int duk_repl_fpclassify(double x) {
8684 duk_double_union u;
8685 duk_uint_fast16_t expt;
8686 duk_small_int_t mzero;
8687
8688 u.d = x;
8689 expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL);
8690 if (expt > 0x0000UL && expt < 0x7ff0UL) {
8691 /* expt values [0x001,0x7fe] = normal */
8692 return DUK_FP_NORMAL;
8693 }
8694
8695 mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0);
8696 if (expt == 0x0000UL) {
8697 /* expt 0x000 is zero/subnormal */
8698 if (mzero) {
8699 return DUK_FP_ZERO;
8700 } else {
8701 return DUK_FP_SUBNORMAL;
8702 }
8703 } else {
8704 /* expt 0xfff is infinite/nan */
8705 if (mzero) {
8706 return DUK_FP_INFINITE;
8707 } else {
8708 return DUK_FP_NAN;
8709 }
8710 }
8711}
8712#endif
8713
8714#if defined(DUK_USE_REPL_SIGNBIT)
8715DUK_INTERNAL int duk_repl_signbit(double x) {
8716 duk_double_union u;
8717 u.d = x;
8718 return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL);
8719}
8720#endif
8721
8722#if defined(DUK_USE_REPL_ISFINITE)
8723DUK_INTERNAL int duk_repl_isfinite(double x) {
8724 int c = DUK_FPCLASSIFY(x);
8725 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
8726 return 0;
8727 } else {
8728 return 1;
8729 }
8730}
8731#endif
8732
8733#if defined(DUK_USE_REPL_ISNAN)
8734DUK_INTERNAL int duk_repl_isnan(double x) {
8735 int c = DUK_FPCLASSIFY(x);
8736 return (c == DUK_FP_NAN);
8737}
8738#endif
8739
8740#if defined(DUK_USE_REPL_ISINF)
8741DUK_INTERNAL int duk_repl_isinf(double x) {
8742 int c = DUK_FPCLASSIFY(x);
8743 return (c == DUK_FP_INFINITE);
8744}
8745#endif
8746#line 1 "duk_strings.c"
8747/*
8748 * Shared error message strings
8749 *
8750 * To minimize code footprint, try to share error messages inside Duktape
8751 * code. Modern compilers will do this automatically anyway, this is mostly
8752 * for older compilers.
8753 */
8754
8755/* include removed: duk_internal.h */
8756
8757/* Mostly API and built-in method related */
8758DUK_INTERNAL const char *duk_str_internal_error = "internal error";
8759DUK_INTERNAL const char *duk_str_invalid_count = "invalid count";
8760DUK_INTERNAL const char *duk_str_invalid_call_args = "invalid call args";
8761DUK_INTERNAL const char *duk_str_not_constructable = "not constructable";
8762DUK_INTERNAL const char *duk_str_not_callable = "not callable";
8763DUK_INTERNAL const char *duk_str_not_extensible = "not extensible";
8764DUK_INTERNAL const char *duk_str_not_writable = "not writable";
8765DUK_INTERNAL const char *duk_str_not_configurable = "not configurable";
8766
8767DUK_INTERNAL const char *duk_str_invalid_context = "invalid context";
8768DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack";
8769DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */
8770DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type";
8771DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed";
8772DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range";
8773DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible";
8774DUK_INTERNAL const char *duk_str_string_too_long = "string too long";
8775DUK_INTERNAL const char *duk_str_buffer_too_long = "buffer too long";
8776DUK_INTERNAL const char *duk_str_sprintf_too_long = "sprintf message too long";
8777DUK_INTERNAL const char *duk_str_alloc_failed = "alloc failed";
8778DUK_INTERNAL const char *duk_str_pop_too_many = "attempt to pop too many entries";
8779DUK_INTERNAL const char *duk_str_wrong_buffer_type = "wrong buffer type";
8780DUK_INTERNAL const char *duk_str_encode_failed = "encode failed";
8781DUK_INTERNAL const char *duk_str_decode_failed = "decode failed";
8782DUK_INTERNAL const char *duk_str_no_sourcecode = "no sourcecode";
8783DUK_INTERNAL const char *duk_str_concat_result_too_long = "concat result too long";
8784DUK_INTERNAL const char *duk_str_unimplemented = "unimplemented";
8785DUK_INTERNAL const char *duk_str_unsupported = "unsupported";
8786DUK_INTERNAL const char *duk_str_array_length_over_2g = "array length over 2G";
8787
8788/* JSON */
8789DUK_INTERNAL const char *duk_str_fmt_ptr = "%p";
8790DUK_INTERNAL const char *duk_str_fmt_invalid_json = "invalid json (at offset %ld)";
8791DUK_INTERNAL const char *duk_str_jsondec_reclimit = "json decode recursion limit";
8792DUK_INTERNAL const char *duk_str_jsonenc_reclimit = "json encode recursion limit";
8793DUK_INTERNAL const char *duk_str_cyclic_input = "cyclic input";
8794
8795/* Object property access */
8796DUK_INTERNAL const char *duk_str_proxy_revoked = "proxy revoked";
8797DUK_INTERNAL const char *duk_str_invalid_base = "invalid base value";
8798DUK_INTERNAL const char *duk_str_strict_caller_read = "attempt to read strict 'caller'";
8799DUK_INTERNAL const char *duk_str_proxy_rejected = "proxy rejected";
8800DUK_INTERNAL const char *duk_str_invalid_array_length = "invalid array length";
8801DUK_INTERNAL const char *duk_str_array_length_write_failed = "array length write failed";
8802DUK_INTERNAL const char *duk_str_array_length_not_writable = "array length non-writable";
8803DUK_INTERNAL const char *duk_str_setter_undefined = "setter undefined";
8804DUK_INTERNAL const char *duk_str_redefine_virt_prop = "attempt to redefine virtual property";
8805DUK_INTERNAL const char *duk_str_invalid_descriptor = "invalid descriptor";
8806DUK_INTERNAL const char *duk_str_property_is_virtual = "property is virtual";
8807
8808/* Compiler */
8809DUK_INTERNAL const char *duk_str_parse_error = "parse error";
8810DUK_INTERNAL const char *duk_str_duplicate_label = "duplicate label";
8811DUK_INTERNAL const char *duk_str_invalid_label = "invalid label";
8812DUK_INTERNAL const char *duk_str_invalid_array_literal = "invalid array literal";
8813DUK_INTERNAL const char *duk_str_invalid_object_literal = "invalid object literal";
8814DUK_INTERNAL const char *duk_str_invalid_var_declaration = "invalid variable declaration";
8815DUK_INTERNAL const char *duk_str_cannot_delete_identifier = "cannot delete identifier";
8816DUK_INTERNAL const char *duk_str_invalid_expression = "invalid expression";
8817DUK_INTERNAL const char *duk_str_invalid_lvalue = "invalid lvalue";
8818DUK_INTERNAL const char *duk_str_expected_identifier = "expected identifier";
8819DUK_INTERNAL const char *duk_str_empty_expr_not_allowed = "empty expression not allowed";
8820DUK_INTERNAL const char *duk_str_invalid_for = "invalid for statement";
8821DUK_INTERNAL const char *duk_str_invalid_switch = "invalid switch statement";
8822DUK_INTERNAL const char *duk_str_invalid_break_cont_label = "invalid break/continue label";
8823DUK_INTERNAL const char *duk_str_invalid_return = "invalid return";
8824DUK_INTERNAL const char *duk_str_invalid_try = "invalid try";
8825DUK_INTERNAL const char *duk_str_invalid_throw = "invalid throw";
8826DUK_INTERNAL const char *duk_str_with_in_strict_mode = "with in strict mode";
8827DUK_INTERNAL const char *duk_str_func_stmt_not_allowed = "function statement not allowed";
8828DUK_INTERNAL const char *duk_str_unterminated_stmt = "unterminated statement";
8829DUK_INTERNAL const char *duk_str_invalid_arg_name = "invalid argument name";
8830DUK_INTERNAL const char *duk_str_invalid_func_name = "invalid function name";
8831DUK_INTERNAL const char *duk_str_invalid_getset_name = "invalid getter/setter name";
8832DUK_INTERNAL const char *duk_str_func_name_required = "function name required";
8833
8834/* Regexp */
8835DUK_INTERNAL const char *duk_str_invalid_quantifier_no_atom = "quantifier without preceding atom";
8836DUK_INTERNAL const char *duk_str_invalid_quantifier_values = "quantifier values invalid (qmin > qmax)";
8837DUK_INTERNAL const char *duk_str_quantifier_too_many_copies = "quantifier expansion requires too many atom copies";
8838DUK_INTERNAL const char *duk_str_unexpected_closing_paren = "unexpected closing parenthesis";
8839DUK_INTERNAL const char *duk_str_unexpected_end_of_pattern = "unexpected end of pattern";
8840DUK_INTERNAL const char *duk_str_unexpected_regexp_token = "unexpected token in regexp";
8841DUK_INTERNAL const char *duk_str_invalid_regexp_flags = "invalid regexp flags";
8842DUK_INTERNAL const char *duk_str_invalid_backrefs = "invalid backreference(s)";
8843
8844/* Limits */
8845DUK_INTERNAL const char *duk_str_valstack_limit = "valstack limit";
8846DUK_INTERNAL const char *duk_str_callstack_limit = "callstack limit";
8847DUK_INTERNAL const char *duk_str_catchstack_limit = "catchstack limit";
8848DUK_INTERNAL const char *duk_str_prototype_chain_limit = "prototype chain limit";
8849DUK_INTERNAL const char *duk_str_bound_chain_limit = "function call bound chain limit";
8850DUK_INTERNAL const char *duk_str_c_callstack_limit = "C call stack depth limit";
8851DUK_INTERNAL const char *duk_str_compiler_recursion_limit = "compiler recursion limit";
8852DUK_INTERNAL const char *duk_str_bytecode_limit = "bytecode limit";
8853DUK_INTERNAL const char *duk_str_reg_limit = "register limit";
8854DUK_INTERNAL const char *duk_str_temp_limit = "temp limit";
8855DUK_INTERNAL const char *duk_str_const_limit = "const limit";
8856DUK_INTERNAL const char *duk_str_func_limit = "function limit";
8857DUK_INTERNAL const char *duk_str_regexp_compiler_recursion_limit = "regexp compiler recursion limit";
8858DUK_INTERNAL const char *duk_str_regexp_executor_recursion_limit = "regexp executor recursion limit";
8859DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit";
8860
8861/* Misc */
8862#line 1 "duk_debug_macros.c"
8863/*
8864 * Debugging macro calls.
8865 */
8866
8867/* include removed: duk_internal.h */
8868
8869#ifdef DUK_USE_DEBUG
8870
8871/*
8872 * Debugging enabled
8873 */
8874
8875#include <stdio.h>
8876#include <stdlib.h>
8877#include <stdarg.h>
8878
8879#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
8880DUK_LOCAL char duk__debug_buf[DUK__DEBUG_BUFSIZE];
8881
8882DUK_LOCAL const char *duk__get_level_string(duk_small_int_t level) {
8883 switch ((int) level) {
8884 case DUK_LEVEL_DEBUG:
8885 return "D";
8886 case DUK_LEVEL_DDEBUG:
8887 return "DD";
8888 case DUK_LEVEL_DDDEBUG:
8889 return "DDD";
8890 }
8891 return "???";
8892}
8893
8894#ifdef DUK_USE_DPRINT_COLORS
8895
8896/* http://en.wikipedia.org/wiki/ANSI_escape_code */
8897#define DUK__TERM_REVERSE "\x1b[7m"
8898#define DUK__TERM_BRIGHT "\x1b[1m"
8899#define DUK__TERM_RESET "\x1b[0m"
8900#define DUK__TERM_BLUE "\x1b[34m"
8901#define DUK__TERM_RED "\x1b[31m"
8902
8903DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
8904 DUK_UNREF(level);
8905 return (const char *) DUK__TERM_RED;
8906}
8907
8908DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
8909 switch ((int) level) {
8910 case DUK_LEVEL_DEBUG:
8911 return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT);
8912 case DUK_LEVEL_DDEBUG:
8913 return (const char *) (DUK__TERM_RESET);
8914 case DUK_LEVEL_DDDEBUG:
8915 return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE);
8916 }
8917 return (const char *) DUK__TERM_RESET;
8918}
8919
8920DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
8921 DUK_UNREF(level);
8922 return (const char *) DUK__TERM_RESET;
8923}
8924
8925#else
8926
8927DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
8928 DUK_UNREF(level);
8929 return (const char *) "";
8930}
8931
8932DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
8933 DUK_UNREF(level);
8934 return (const char *) "";
8935}
8936
8937DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
8938 DUK_UNREF(level);
8939 return (const char *) "";
8940}
8941
8942#endif /* DUK_USE_DPRINT_COLORS */
8943
8944#ifdef DUK_USE_VARIADIC_MACROS
8945
8946DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
8947 va_list ap;
8948
8949 va_start(ap, fmt);
8950
8951 DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
8952 duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
8953
8954 DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n",
8955 (const char *) duk__get_term_1(level),
8956 (const char *) duk__get_level_string(level),
8957 (const char *) file,
8958 (long) line,
8959 (const char *) func,
8960 (const char *) duk__get_term_2(level),
8961 (const char *) duk__debug_buf,
8962 (const char *) duk__get_term_3(level));
8963 DUK_FFLUSH(DUK_STDERR);
8964
8965 va_end(ap);
8966}
8967
8968#else /* DUK_USE_VARIADIC_MACROS */
8969
8970DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
8971DUK_INTERNAL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
8972DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
8973DUK_INTERNAL duk_small_int_t duk_debug_level_stash;
8974
8975DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
8976 va_list ap;
8977 duk_small_int_t level = duk_debug_level_stash;
8978
8979 va_start(ap, fmt);
8980
8981 DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
8982 duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
8983
8984 DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n",
8985 (const char *) duk__get_term_1(level),
8986 (const char *) duk__get_level_string(duk_debug_level_stash),
8987 (const char *) duk_debug_file_stash,
8988 (const char *) duk_debug_line_stash,
8989 (const char *) duk_debug_func_stash,
8990 (const char *) duk__get_term_2(level),
8991 (const char *) duk__debug_buf,
8992 (const char *) duk__get_term_3(level));
8993 DUK_FFLUSH(DUK_STDERR);
8994
8995 va_end(ap);
8996}
8997
8998#endif /* DUK_USE_VARIADIC_MACROS */
8999
9000#else /* DUK_USE_DEBUG */
9001
9002/*
9003 * Debugging disabled
9004 */
9005
9006#endif /* DUK_USE_DEBUG */
9007#line 1 "duk_builtins.c"
9008/*
9009 * Automatically generated by genbuiltins.py, do not edit!
9010 */
9011
9012/* include removed: duk_internal.h */
9013
9014#if defined(DUK_USE_ROM_STRINGS)
9015#error ROM support not enabled, rerun make_dist.py with --rom-support
9016#else /* DUK_USE_ROM_STRINGS */
9017DUK_INTERNAL const duk_uint8_t duk_strings_data[1049] = {
901879,104,209,144,168,105,6,78,182,139,90,122,8,154,140,35,103,35,117,193,73,
90195,52,116,180,104,166,135,52,189,4,98,12,27,178,156,80,211,31,161,115,150,
902064,52,221,109,24,18,68,157,24,38,67,118,36,55,73,119,151,164,140,93,18,117,
9021128,153,201,228,201,205,2,250,8,196,24,232,104,82,146,40,232,193,48,118,
9022168,37,147,212,54,127,113,208,70,32,194,187,68,54,127,113,208,70,32,196,
9023123,68,54,127,113,209,44,12,121,7,208,70,32,194,186,134,207,236,126,219,
9024160,140,65,133,246,136,108,254,199,237,186,8,196,24,87,80,217,253,159,217,
9025116,17,136,48,190,209,13,159,217,253,151,65,24,131,12,233,86,224,79,236,
9026254,203,160,140,65,134,116,171,112,39,246,223,105,208,70,32,193,140,183,4,
902711,55,92,20,244,141,169,186,50,11,164,109,77,208,208,165,36,79,215,185,13,
9028153,34,110,204,241,32,6,66,84,11,112,200,84,52,157,124,92,242,70,120,45,64,
9029186,17,22,138,38,0,172,140,19,154,84,26,145,0,86,69,17,180,97,34,0,172,132,
903075,144,215,77,221,91,132,5,147,178,156,80,211,30,160,93,9,215,21,115,119,
9031169,49,75,211,138,26,101,205,222,68,157,47,78,40,105,151,55,120,204,156,
9032189,56,161,166,52,157,72,136,138,65,154,232,147,162,4,136,150,81,115,66,
9033208,210,37,96,148,250,134,140,151,39,212,125,255,221,125,73,80,209,146,233,
9034124,93,55,79,15,34,196,230,202,113,160,166,232,157,132,148,128,98,28,46,
9035114,200,6,153,180,96,73,19,74,113,67,76,103,5,36,20,211,70,140,133,67,72,
903649,245,160,235,81,212,52,168,106,39,132,253,111,80,210,161,168,158,5,245,
9037191,96,31,172,15,208,23,226,190,131,232,62,131,232,11,251,127,93,245,223,
903893,251,172,234,27,80,45,3,250,14,140,19,34,65,19,81,132,108,228,97,1,107,
903933,12,32,45,100,136,206,9,12,196,155,134,69,146,100,235,226,231,146,51,194,
904072,218,48,145,4,200,119,89,189,81,49,39,72,147,235,226,233,186,120,121,58,
9041226,167,90,124,93,55,107,71,137,33,68,68,130,64,206,75,189,209,156,144,84,
904244,141,3,8,137,187,178,156,80,211,26,110,242,100,230,146,120,121,8,48,76,6,
904389,26,105,157,65,196,201,213,145,166,153,212,28,76,157,113,75,34,78,62,14,
904438,73,105,228,142,136,178,48,141,152,228,73,150,83,0,148,39,137,75,67,73,
9045214,209,129,36,85,190,206,32,17,6,9,128,141,3,8,130,161,100,235,64,194,24,
904652,41,73,19,189,200,108,201,19,111,181,2,232,66,239,173,37,230,157,244,56,
9047153,4,225,145,27,233,93,22,1,114,62,251,80,69,128,121,247,213,146,228,109,
904879,190,212,17,35,106,125,246,78,164,68,68,111,175,23,217,45,13,33,119,208,
904968,210,38,250,192,61,91,233,80,208,45,25,36,81,190,156,13,26,201,19,239,
9050162,2,214,66,31,125,153,226,64,13,27,236,72,96,130,68,62,251,48,68,196,153,
9051119,217,157,18,56,156,199,161,100,42,26,250,77,36,140,122,40,144,19,34,9,
905224,246,103,139,172,150,56,125,145,1,17,29,44,112,250,183,0,100,24,200,218,
9053140,228,185,130,9,19,237,190,208,73,184,146,35,68,146,163,8,50,178,99,136,
905444,89,196,2,33,70,64,208,196,67,74,226,88,17,105,73,24,186,37,40,38,5,133,
9055161,89,4,183,25,115,119,86,227,118,83,138,26,103,255,223,209,106,141,25,11,
9056244,95,117,56,208,159,250,223,251,250,45,52,13,250,47,186,156,104,79,253,
9057111,253,253,22,144,210,253,23,221,78,52,39,254,187,254,254,139,77,67,75,
9058244,95,117,56,208,159,250,239,251,250,45,22,141,23,209,125,212,227,66,127,
9059235,63,239,69,163,69,247,83,141,9,255,165,12,72,5,16,64,145,10,32,76,71,64,
9060156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,147,32,134,226,
906117,114,33,202,134,129,107,192,202,232,160,180,104,166,135,52,72,40,144,213,
906233,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,98,57,38,116,72,
9063179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,42,228,12,182,
906458,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,94,100,104,
9065228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,46,68,82,24,
9066245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,33,223,20,
906784,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,130,44,96,
9068};
9069#endif /* DUK_USE_ROM_STRINGS */
9070
9071#if defined(DUK_USE_ROM_OBJECTS)
9072#error ROM support not enabled, rerun make_dist.py with --rom-support
9073#else /* DUK_USE_ROM_OBJECTS */
9074/* native functions: 149 */
9075DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
9076 duk_bi_array_constructor,
9077 duk_bi_array_constructor_is_array,
9078 duk_bi_array_prototype_concat,
9079 duk_bi_array_prototype_indexof_shared,
9080 duk_bi_array_prototype_iter_shared,
9081 duk_bi_array_prototype_join_shared,
9082 duk_bi_array_prototype_pop,
9083 duk_bi_array_prototype_push,
9084 duk_bi_array_prototype_reduce_shared,
9085 duk_bi_array_prototype_reverse,
9086 duk_bi_array_prototype_shift,
9087 duk_bi_array_prototype_slice,
9088 duk_bi_array_prototype_sort,
9089 duk_bi_array_prototype_splice,
9090 duk_bi_array_prototype_to_string,
9091 duk_bi_array_prototype_unshift,
9092 duk_bi_arraybuffer_constructor,
9093 duk_bi_arraybuffer_isview,
9094 duk_bi_boolean_constructor,
9095 duk_bi_boolean_prototype_tostring_shared,
9096 duk_bi_buffer_compare_shared,
9097 duk_bi_buffer_constructor,
9098 duk_bi_buffer_prototype_tostring_shared,
9099 duk_bi_buffer_readfield,
9100 duk_bi_buffer_slice_shared,
9101 duk_bi_buffer_writefield,
9102 duk_bi_dataview_constructor,
9103 duk_bi_date_constructor,
9104 duk_bi_date_constructor_now,
9105 duk_bi_date_constructor_parse,
9106 duk_bi_date_constructor_utc,
9107 duk_bi_date_prototype_get_shared,
9108 duk_bi_date_prototype_get_timezone_offset,
9109 duk_bi_date_prototype_set_shared,
9110 duk_bi_date_prototype_set_time,
9111 duk_bi_date_prototype_to_json,
9112 duk_bi_date_prototype_tostring_shared,
9113 duk_bi_date_prototype_value_of,
9114 duk_bi_duktape_object_act,
9115 duk_bi_duktape_object_compact,
9116 duk_bi_duktape_object_dec,
9117 duk_bi_duktape_object_enc,
9118 duk_bi_duktape_object_fin,
9119 duk_bi_duktape_object_gc,
9120 duk_bi_duktape_object_info,
9121 duk_bi_error_constructor_shared,
9122 duk_bi_error_prototype_filename_getter,
9123 duk_bi_error_prototype_filename_setter,
9124 duk_bi_error_prototype_linenumber_getter,
9125 duk_bi_error_prototype_linenumber_setter,
9126 duk_bi_error_prototype_stack_getter,
9127 duk_bi_error_prototype_stack_setter,
9128 duk_bi_error_prototype_to_string,
9129 duk_bi_function_constructor,
9130 duk_bi_function_prototype,
9131 duk_bi_function_prototype_apply,
9132 duk_bi_function_prototype_bind,
9133 duk_bi_function_prototype_call,
9134 duk_bi_function_prototype_to_string,
9135 duk_bi_global_object_decode_uri,
9136 duk_bi_global_object_decode_uri_component,
9137 duk_bi_global_object_encode_uri,
9138 duk_bi_global_object_encode_uri_component,
9139 duk_bi_global_object_escape,
9140 duk_bi_global_object_eval,
9141 duk_bi_global_object_is_finite,
9142 duk_bi_global_object_is_nan,
9143 duk_bi_global_object_parse_float,
9144 duk_bi_global_object_parse_int,
9145 duk_bi_global_object_print_helper,
9146 duk_bi_global_object_require,
9147 duk_bi_global_object_unescape,
9148 duk_bi_json_object_parse,
9149 duk_bi_json_object_stringify,
9150 duk_bi_logger_constructor,
9151 duk_bi_logger_prototype_fmt,
9152 duk_bi_logger_prototype_log_shared,
9153 duk_bi_logger_prototype_raw,
9154 duk_bi_math_object_max,
9155 duk_bi_math_object_min,
9156 duk_bi_math_object_onearg_shared,
9157 duk_bi_math_object_random,
9158 duk_bi_math_object_twoarg_shared,
9159 duk_bi_nodejs_buffer_byte_length,
9160 duk_bi_nodejs_buffer_concat,
9161 duk_bi_nodejs_buffer_constructor,
9162 duk_bi_nodejs_buffer_copy,
9163 duk_bi_nodejs_buffer_fill,
9164 duk_bi_nodejs_buffer_is_buffer,
9165 duk_bi_nodejs_buffer_is_encoding,
9166 duk_bi_nodejs_buffer_tojson,
9167 duk_bi_nodejs_buffer_tostring,
9168 duk_bi_nodejs_buffer_write,
9169 duk_bi_number_constructor,
9170 duk_bi_number_prototype_to_exponential,
9171 duk_bi_number_prototype_to_fixed,
9172 duk_bi_number_prototype_to_locale_string,
9173 duk_bi_number_prototype_to_precision,
9174 duk_bi_number_prototype_to_string,
9175 duk_bi_number_prototype_value_of,
9176 duk_bi_object_constructor,
9177 duk_bi_object_constructor_create,
9178 duk_bi_object_constructor_define_properties,
9179 duk_bi_object_constructor_define_property,
9180 duk_bi_object_constructor_get_own_property_descriptor,
9181 duk_bi_object_constructor_is_extensible,
9182 duk_bi_object_constructor_is_sealed_frozen_shared,
9183 duk_bi_object_constructor_keys_shared,
9184 duk_bi_object_constructor_prevent_extensions,
9185 duk_bi_object_constructor_seal_freeze_shared,
9186 duk_bi_object_getprototype_shared,
9187 duk_bi_object_prototype_has_own_property,
9188 duk_bi_object_prototype_is_prototype_of,
9189 duk_bi_object_prototype_property_is_enumerable,
9190 duk_bi_object_prototype_to_locale_string,
9191 duk_bi_object_prototype_to_string,
9192 duk_bi_object_prototype_value_of,
9193 duk_bi_object_setprototype_shared,
9194 duk_bi_pointer_constructor,
9195 duk_bi_pointer_prototype_tostring_shared,
9196 duk_bi_proxy_constructor,
9197 duk_bi_regexp_constructor,
9198 duk_bi_regexp_prototype_exec,
9199 duk_bi_regexp_prototype_test,
9200 duk_bi_regexp_prototype_to_string,
9201 duk_bi_string_constructor,
9202 duk_bi_string_constructor_from_char_code,
9203 duk_bi_string_prototype_caseconv_shared,
9204 duk_bi_string_prototype_char_at,
9205 duk_bi_string_prototype_char_code_at,
9206 duk_bi_string_prototype_concat,
9207 duk_bi_string_prototype_indexof_shared,
9208 duk_bi_string_prototype_locale_compare,
9209 duk_bi_string_prototype_match,
9210 duk_bi_string_prototype_replace,
9211 duk_bi_string_prototype_search,
9212 duk_bi_string_prototype_slice,
9213 duk_bi_string_prototype_split,
9214 duk_bi_string_prototype_substr,
9215 duk_bi_string_prototype_substring,
9216 duk_bi_string_prototype_to_string,
9217 duk_bi_string_prototype_trim,
9218 duk_bi_thread_constructor,
9219 duk_bi_thread_current,
9220 duk_bi_thread_resume,
9221 duk_bi_thread_yield,
9222 duk_bi_type_error_thrower,
9223 duk_bi_typedarray_constructor,
9224 duk_bi_typedarray_set,
9225};
9226#if defined(DUK_USE_BUILTIN_INITJS)
9227DUK_INTERNAL const duk_uint8_t duk_initjs_data[204] = {
922840,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116,
9229105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101,
9230102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97,
9231108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
9232109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,
9233108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99,
9234108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,
923541,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,79,98,106,
9236101,99,116,46,99,114,101,97,116,101,40,110,117,108,108,41,41,125,41,40,116,
9237104,105,115,44,68,117,107,116,97,112,101,41,59,10,0,
9238};
9239#endif /* DUK_USE_BUILTIN_INITJS */
9240#if defined(DUK_USE_DOUBLE_LE)
9241DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
9242105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
9243152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
9244240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
924514,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
9246203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
9247176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
9248148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
9249243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
925021,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
9251145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
9252158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
9253228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
9254202,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,
9255136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
925640,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
9257200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
9258119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
9259138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
9260166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
926119,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
926217,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
9263100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
926430,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
9265240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
9266236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
9267135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
9268208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
9269240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
927082,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
9271158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
9272135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
9273217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
927446,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
9275230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
9276205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
9277230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
9278237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
9279223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
9280119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
9281195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
9282135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
9283128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
928461,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
9285123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
9286250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
9287102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
9288105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
9289183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
929015,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
9291195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
9292202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
9293131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
9294133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
9295195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
9296121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
9297179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
9298242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
9299148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
9300122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
9301150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
930248,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
9303255,255,255,255,255,253,239,240,153,178,103,95,173,6,101,88,176,0,64,0,0,0,
93040,0,0,3,168,0,0,0,0,0,0,31,15,241,26,19,233,201,169,38,180,91,242,103,70,
9305147,58,77,75,48,0,0,0,0,0,0,60,31,226,51,162,199,131,82,77,104,183,228,206,
9306141,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,
93070,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
9308190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
9309126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
9310247,111,238,56,0,127,199,2,49,72,0,0,0,0,0,0,248,127,180,81,36,4,51,166,
9311248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
9312244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
9313195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
931459,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
931580,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
9316184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
93170,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
9318238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
9319196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
9320171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
932194,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
9322101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
932343,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
9324113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
9325187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
9326251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
9327151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
9328121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
9329167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
933043,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
9331231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
9332211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
9333208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
933415,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
9335189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
9336224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
9337233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
9338200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
933924,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
93400,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
9341240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
9342115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
9343252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
9344111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
9345143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
9346238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
934760,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
9348165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,105,87,20,139,10,191,5,
934964,130,76,156,197,132,1,101,91,91,187,22,176,36,8,28,201,204,160,119,156,
9350253,127,33,23,115,31,193,102,79,142,202,44,15,232,34,182,84,113,95,115,248,
935152,201,241,216,176,139,0,59,148,152,85,239,47,108,254,5,66,76,1,130,212,69,
935279,178,16,148,8,61,58,52,170,49,190,202,6,105,219,251,52,245,7,49,252,22,
9353157,26,85,25,64,205,59,127,102,158,160,246,63,74,7,135,23,53,2,65,48,227,
9354223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
9355211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
935647,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
9357136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
935888,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
935921,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
9360134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
9361191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,12,98,
9362160,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,
936360,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
9364147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
9365252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
9366167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
9367184,2,172,254,0,0,255,171,8,137,144,0,0,0,0,0,0,0,128,68,73,4,195,187,126,
9368226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
93690,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
9370153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
9371163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
9372245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
9373244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
9374207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
9375186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
9376221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
9377179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
9378208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
9379195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
9380119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
9381115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
9382102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
93830,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,
93840,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,
9385151,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,
9386177,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,
9387203,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,
9388128,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,
9389101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
9390143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
9391124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
939239,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
9393100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
939440,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
939557,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
939650,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
939795,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
9398101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
9399150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
9400108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
9401200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
9402186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
9403101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
9404209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
9405181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
940698,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
94072,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
9408213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
9409155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
941067,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
9411203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
941270,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
9413229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
941489,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
941510,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
9416119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
941729,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
9418243,217,167,30,81,132,65,123,242,211,211,42,228,0,
9419};
9420#elif defined(DUK_USE_DOUBLE_BE)
9421DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
9422105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
9423152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
9424240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
942514,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
9426203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
9427176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
9428148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
9429243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
943021,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
9431145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
9432158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
9433228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
9434202,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,
9435136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
943640,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
9437200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
9438119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
9439138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
9440166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
944119,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
944217,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
9443100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
944430,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
9445240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
9446236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
9447135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
9448208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
9449240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
945082,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
9451158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
9452135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
9453217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
945446,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
9455230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
9456205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
9457230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
9458237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
9459223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
9460119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
9461195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
9462135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
9463128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
946461,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
9465123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
9466250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
9467102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
9468105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
9469183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
947015,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
9471195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
9472202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
9473131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
9474133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
9475195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
9476121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
9477179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
9478242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
9479148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
9480122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
9481150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
948248,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,15,
9483253,255,255,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
94840,0,0,67,168,15,255,0,0,0,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
9485147,58,77,75,48,31,252,0,0,0,0,0,0,34,51,162,199,131,82,77,104,183,228,206,
9486141,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,
94870,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
9488190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
9489126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
9490247,111,238,56,0,127,199,2,49,72,127,248,0,0,0,0,0,0,180,81,36,4,51,166,
9491248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
9492244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
9493195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
949459,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
949580,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
9496184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
94970,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
9498238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
9499196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
9500171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
950194,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
9502101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
950343,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
9504113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
9505187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
9506251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
9507151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
9508121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
9509167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
951043,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
9511231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
9512211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
9513208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
951415,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
9515189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
9516224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
9517233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
9518200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
951924,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
95200,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
9521240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
9522115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
9523252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
9524111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
9525143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
9526238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
952760,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
9528165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,64,5,191,10,139,20,87,
9529105,130,76,156,197,132,4,0,38,187,27,187,85,81,104,28,201,204,160,31,243,
953023,33,127,125,28,247,193,102,79,142,202,44,3,255,113,84,118,82,184,47,232,
953152,201,241,216,176,139,0,255,111,45,236,84,155,148,58,5,66,76,4,0,146,31,
9532181,68,66,209,136,61,58,52,170,49,190,202,1,255,53,4,243,51,249,222,108,22,
9533157,26,85,25,64,63,246,160,158,102,127,59,205,74,7,135,23,53,2,65,48,227,
9534223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
9535211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
953647,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
9537136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
953888,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
953921,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
9540134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
9541191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,140,0,0,0,0,
95420,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
954356,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
9544147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
9545252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
9546167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
9547184,2,172,254,0,0,255,171,8,137,144,128,0,0,0,0,0,0,0,68,73,4,195,187,126,
9548226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
95490,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
9550153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
9551163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
9552245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
9553244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
9554207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
9555186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
9556221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
9557179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
9558208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
9559195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
9560119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
9561115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
9562102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
95630,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,
9564255,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,
9565151,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,
9566177,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,
9567203,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,
9568128,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,
9569101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
9570143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
9571124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
957239,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
9573100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
957440,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
957557,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
957650,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
957795,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
9578101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
9579150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
9580108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
9581200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
9582186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
9583101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
9584209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
9585181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
958698,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
95872,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
9588213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
9589155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
959067,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
9591203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
959270,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
9593229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
959489,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
959510,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
9596119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
959729,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
9598243,217,167,30,81,132,65,123,242,211,211,42,228,0,
9599};
9600#elif defined(DUK_USE_DOUBLE_ME)
9601DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
9602105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
9603152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
9604240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
960514,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
9606203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
9607176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
9608148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
9609243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
961021,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
9611145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
9612158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
9613228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
9614202,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,
9615136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
961640,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
9617200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
9618119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
9619138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
9620166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
962119,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
962217,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
9623100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
962430,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
9625240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
9626236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
9627135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
9628208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
9629240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
963082,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
9631158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
9632135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
9633217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
963446,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
9635230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
9636205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
9637230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
9638237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
9639223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
9640119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
9641195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
9642135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
9643128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
964461,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
9645123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
9646250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
9647102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
9648105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
9649183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
965015,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
9651195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
9652202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
9653131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
9654133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
9655195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
9656121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
9657179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
9658242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
9659148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
9660122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
9661150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
966248,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
9663255,253,239,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
966464,0,0,3,168,0,0,31,15,224,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
9665147,58,77,75,48,0,0,60,31,192,0,0,0,34,51,162,199,131,82,77,104,183,228,
9666206,141,38,116,154,150,96,0,0,120,127,128,0,0,0,0,15,248,192,70,40,0,0,0,0,
96670,0,0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,
9668248,190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,
9669167,126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,
967064,247,111,238,56,0,127,199,2,49,72,0,0,248,127,0,0,0,0,180,81,36,4,51,166,
9671248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
9672244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
9673195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
967459,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
967580,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
9676184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
96770,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
9678238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
9679196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
9680171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
968194,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
9682101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
968343,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
9684113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
9685187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
9686251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
9687151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
9688121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
9689167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
969043,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
9691231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
9692211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
9693208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
969415,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
9695189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
9696224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
9697233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
9698200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
969924,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
97000,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
9701240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
9702115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
9703252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
9704111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
9705143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
9706238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
970760,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
9708165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,10,191,5,64,105,87,20,
9709139,130,76,156,197,132,11,22,176,36,1,101,91,91,184,28,201,204,160,33,23,
9710115,31,247,156,253,127,65,102,79,142,202,44,4,113,95,115,255,232,34,182,88,
971152,201,241,216,176,139,1,239,47,108,252,59,148,152,86,5,66,76,15,178,16,
9712148,1,130,212,69,72,61,58,52,170,49,190,202,4,245,7,49,254,105,219,251,52,
971322,157,26,85,25,64,158,160,246,63,205,59,127,102,74,7,135,23,53,2,65,48,
9714227,223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,
9715195,211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,
971615,47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
9717136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
971888,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
971921,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
9720134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
9721191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,12,98,160,0,0,0,
97220,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
972356,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
9724147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
9725252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
9726167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
9727184,2,172,254,0,0,255,171,8,137,144,0,0,0,128,0,0,0,0,68,73,4,195,187,126,
9728226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
97290,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
9730153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
9731163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
9732245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
9733244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
9734207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
9735186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
9736221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
9737179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
9738208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
9739195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
9740119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
9741115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
9742102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
97430,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,
97440,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,
9745151,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,
9746177,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,
9747203,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,
9748128,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,
9749101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
9750143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
9751124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
975239,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
9753100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
975440,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
975557,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
975650,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
975795,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
9758101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
9759150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
9760108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
9761200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
9762186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
9763101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
9764209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
9765181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
976698,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
97672,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
9768213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
9769155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
977067,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
9771203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
977270,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
9773229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
977489,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
977510,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
9776119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
977729,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
9778243,217,167,30,81,132,65,123,242,211,211,42,228,0,
9779};
9780#else
9781#error invalid endianness defines
9782#endif
9783#endif /* DUK_USE_ROM_OBJECTS */
9784#line 1 "duk_error_macros.c"
9785/*
9786 * Error, fatal, and panic handling.
9787 */
9788
9789/* include removed: duk_internal.h */
9790
9791#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
9792
9793#if defined(DUK_USE_VERBOSE_ERRORS)
9794
9795DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
9796 va_list ap;
9797 char msg[DUK__ERRFMT_BUFSIZE];
9798 va_start(ap, fmt);
9799 (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
9800 msg[sizeof(msg) - 1] = (char) 0;
9801 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
9802 va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
9803}
9804
9805DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
9806 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
9807}
9808
9809#else /* DUK_USE_VERBOSE_ERRORS */
9810
9811DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
9812 duk_err_create_and_throw(thr, code);
9813}
9814
9815#endif /* DUK_USE_VERBOSE_ERRORS */
9816
9817/*
9818 * Error throwing helpers
9819 */
9820
9821#if defined(DUK_USE_VERBOSE_ERRORS)
9822#if defined(DUK_USE_PARANOID_ERRORS)
9823DUK_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) {
9824 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
9825 expect_name, duk_get_type_name((duk_context *) thr, index), (long) index);
9826}
9827#else
9828DUK_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) {
9829 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
9830 expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index);
9831}
9832#endif
9833DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9834 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
9835}
9836DUK_INTERNAL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index) {
9837 DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index));
9838}
9839DUK_INTERNAL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9840 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_API_ERROR, message);
9841}
9842DUK_INTERNAL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
9843 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNIMPLEMENTED_ERROR, DUK_STR_UNIMPLEMENTED);
9844}
9845#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
9846DUK_INTERNAL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
9847 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNSUPPORTED_ERROR, DUK_STR_UNSUPPORTED);
9848}
9849#endif
9850DUK_INTERNAL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
9851 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, DUK_STR_INTERNAL_ERROR);
9852}
9853DUK_INTERNAL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9854 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, message);
9855}
9856DUK_INTERNAL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9857 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ALLOC_ERROR, message);
9858}
9859#else
9860/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
9861 * when non-verbose errors are used.
9862 */
9863DUK_INTERNAL void duk_err_type(duk_hthread *thr) {
9864 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_TYPE_ERROR, NULL);
9865}
9866DUK_INTERNAL void duk_err_api(duk_hthread *thr) {
9867 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_API_ERROR, NULL);
9868}
9869DUK_INTERNAL void duk_err_range(duk_hthread *thr) {
9870 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_RANGE_ERROR, NULL);
9871}
9872DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) {
9873 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_SYNTAX_ERROR, NULL);
9874}
9875DUK_INTERNAL void duk_err_unimplemented(duk_hthread *thr) {
9876 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNIMPLEMENTED_ERROR, NULL);
9877}
9878DUK_INTERNAL void duk_err_unsupported(duk_hthread *thr) {
9879 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNSUPPORTED_ERROR, NULL);
9880}
9881DUK_INTERNAL void duk_err_internal(duk_hthread *thr) {
9882 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_INTERNAL_ERROR, NULL);
9883}
9884DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) {
9885 DUK_ERROR_RAW(thr, NULL, thr, DUK_ERR_ALLOC_ERROR, NULL);
9886}
9887#endif
9888
9889/*
9890 * Default fatal error handler
9891 */
9892
9893DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
9894 DUK_UNREF(ctx);
9895#if defined(DUK_USE_FILE_IO)
9896 DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null"));
9897 DUK_FFLUSH(DUK_STDERR);
9898#else
9899 /* omit print */
9900#endif
9901 DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code));
9902 DUK_PANIC(code, msg);
9903 DUK_UNREACHABLE();
9904}
9905
9906/*
9907 * Default panic handler
9908 */
9909
9910#if !defined(DUK_USE_PANIC_HANDLER)
9911DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) {
9912#if defined(DUK_USE_FILE_IO)
9913 DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s ("
9914#if defined(DUK_USE_PANIC_ABORT)
9915 "calling abort"
9916#elif defined(DUK_USE_PANIC_EXIT)
9917 "calling exit"
9918#elif defined(DUK_USE_PANIC_SEGFAULT)
9919 "segfaulting on purpose"
9920#else
9921#error no DUK_USE_PANIC_xxx macro defined
9922#endif
9923 ")\n", (long) code, (const char *) (msg ? msg : "null"));
9924 DUK_FFLUSH(DUK_STDERR);
9925#else
9926 /* omit print */
9927 DUK_UNREF(code);
9928 DUK_UNREF(msg);
9929#endif
9930
9931#if defined(DUK_USE_PANIC_ABORT)
9932 DUK_ABORT();
9933#elif defined(DUK_USE_PANIC_EXIT)
9934 DUK_EXIT(-1);
9935#elif defined(DUK_USE_PANIC_SEGFAULT)
9936 /* exit() afterwards to satisfy "noreturn" */
9937 DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */
9938 DUK_EXIT(-1);
9939#else
9940#error no DUK_USE_PANIC_xxx macro defined
9941#endif
9942
9943 DUK_UNREACHABLE();
9944}
9945#endif /* !DUK_USE_PANIC_HANDLER */
9946
9947#undef DUK__ERRFMT_BUFSIZE
9948#line 1 "duk_unicode_support.c"
9949/*
9950 * Various Unicode help functions for character classification predicates,
9951 * case conversion, decoding, etc.
9952 */
9953
9954/* include removed: duk_internal.h */
9955
9956/*
9957 * Fast path tables
9958 */
9959
9960#if defined(DUK_USE_IDCHAR_FASTPATH)
9961DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = {
9962 /* 0: not IdentifierStart or IdentifierPart
9963 * 1: IdentifierStart and IdentifierPart
9964 * -1: IdentifierPart only
9965 */
9966 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */
9967 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */
9968 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */
9969 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */
9970 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */
9971 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */
9972 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */
9973 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */
9974};
9975#endif
9976
9977/*
9978 * XUTF-8 and CESU-8 encoding/decoding
9979 */
9980
9981DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) {
9982 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
9983 if (x < 0x80UL) {
9984 /* 7 bits */
9985 return 1;
9986 } else if (x < 0x800UL) {
9987 /* 11 bits */
9988 return 2;
9989 } else if (x < 0x10000UL) {
9990 /* 16 bits */
9991 return 3;
9992 } else if (x < 0x200000UL) {
9993 /* 21 bits */
9994 return 4;
9995 } else if (x < 0x4000000UL) {
9996 /* 26 bits */
9997 return 5;
9998 } else if (x < (duk_ucodepoint_t) 0x80000000UL) {
9999 /* 31 bits */
10000 return 6;
10001 } else {
10002 /* 36 bits */
10003 return 7;
10004 }
10005}
10006
10007#if defined(DUK_USE_ASSERTIONS)
10008DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) {
10009 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10010 if (x < 0x80UL) {
10011 /* 7 bits */
10012 return 1;
10013 } else if (x < 0x800UL) {
10014 /* 11 bits */
10015 return 2;
10016 } else if (x < 0x10000UL) {
10017 /* 16 bits */
10018 return 3;
10019 } else {
10020 /* Encoded as surrogate pair, each encoding to 3 bytes for
10021 * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes
10022 * too, see duk_unicode_encode_cesu8().
10023 */
10024 return 3 + 3;
10025 }
10026}
10027#endif /* DUK_USE_ASSERTIONS */
10028
10029DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = {
10030 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
10031};
10032
10033/* Encode to extended UTF-8; 'out' must have space for at least
10034 * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any
10035 * 32-bit (unsigned) codepoint.
10036 */
10037DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) {
10038 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10039 duk_small_int_t len;
10040 duk_uint8_t marker;
10041 duk_small_int_t i;
10042
10043 len = duk_unicode_get_xutf8_length(cp);
10044 DUK_ASSERT(len > 0);
10045
10046 marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */
10047
10048 i = len;
10049 DUK_ASSERT(i > 0);
10050 do {
10051 i--;
10052 if (i > 0) {
10053 out[i] = (duk_uint8_t) (0x80 + (x & 0x3f));
10054 x >>= 6;
10055 } else {
10056 /* Note: masking of 'x' is not necessary because of
10057 * range check and shifting -> no bits overlapping
10058 * the marker should be set.
10059 */
10060 out[0] = (duk_uint8_t) (marker + x);
10061 }
10062 } while (i > 0);
10063
10064 return len;
10065}
10066
10067/* Encode to CESU-8; 'out' must have space for at least
10068 * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF
10069 * will encode to garbage but won't overwrite the output buffer.
10070 */
10071DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) {
10072 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10073 duk_small_int_t len;
10074
10075 if (x < 0x80UL) {
10076 out[0] = (duk_uint8_t) x;
10077 len = 1;
10078 } else if (x < 0x800UL) {
10079 out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f));
10080 out[1] = (duk_uint8_t) (0x80 + (x & 0x3f));
10081 len = 2;
10082 } else if (x < 0x10000UL) {
10083 /* surrogate pairs get encoded here */
10084 out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f));
10085 out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f));
10086 out[2] = (duk_uint8_t) (0x80 + (x & 0x3f));
10087 len = 3;
10088 } else {
10089 /*
10090 * Unicode codepoints above U+FFFF are encoded as surrogate
10091 * pairs here. This ensures that all CESU-8 codepoints are
10092 * 16-bit values as expected in Ecmascript. The surrogate
10093 * pairs always get a 3-byte encoding (each) in CESU-8.
10094 * See: http://en.wikipedia.org/wiki/Surrogate_pair
10095 *
10096 * 20-bit codepoint, 10 bits (A and B) per surrogate pair:
10097 *
10098 * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB
10099 * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff))
10100 * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff))
10101 *
10102 * Encoded into CESU-8:
10103 *
10104 * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f))
10105 * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f))
10106 * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f))
10107 * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f))
10108 * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f))
10109 * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f))
10110 *
10111 * Note that 0x10000 must be subtracted first. The code below
10112 * avoids the sp1, sp2 temporaries which saves around 20 bytes
10113 * of code.
10114 */
10115
10116 x -= 0x10000UL;
10117
10118 out[0] = (duk_uint8_t) (0xed);
10119 out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f));
10120 out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f));
10121 out[3] = (duk_uint8_t) (0xed);
10122 out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f));
10123 out[5] = (duk_uint8_t) (0x80 + (x & 0x3f));
10124 len = 6;
10125 }
10126
10127 return len;
10128}
10129
10130/* Decode helper. Return zero on error. */
10131DUK_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) {
10132 const duk_uint8_t *p;
10133 duk_uint32_t res;
10134 duk_uint_fast8_t ch;
10135 duk_small_int_t n;
10136
10137 DUK_UNREF(thr);
10138
10139 p = *ptr;
10140 if (p < ptr_start || p >= ptr_end) {
10141 goto fail;
10142 }
10143
10144 /*
10145 * UTF-8 decoder which accepts longer than standard byte sequences.
10146 * This allows full 32-bit code points to be used.
10147 */
10148
10149 ch = (duk_uint_fast8_t) (*p++);
10150 if (ch < 0x80) {
10151 /* 0xxx xxxx [7 bits] */
10152 res = (duk_uint32_t) (ch & 0x7f);
10153 n = 0;
10154 } else if (ch < 0xc0) {
10155 /* 10xx xxxx -> invalid */
10156 goto fail;
10157 } else if (ch < 0xe0) {
10158 /* 110x xxxx 10xx xxxx [11 bits] */
10159 res = (duk_uint32_t) (ch & 0x1f);
10160 n = 1;
10161 } else if (ch < 0xf0) {
10162 /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */
10163 res = (duk_uint32_t) (ch & 0x0f);
10164 n = 2;
10165 } else if (ch < 0xf8) {
10166 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */
10167 res = (duk_uint32_t) (ch & 0x07);
10168 n = 3;
10169 } else if (ch < 0xfc) {
10170 /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */
10171 res = (duk_uint32_t) (ch & 0x03);
10172 n = 4;
10173 } else if (ch < 0xfe) {
10174 /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */
10175 res = (duk_uint32_t) (ch & 0x01);
10176 n = 5;
10177 } else if (ch < 0xff) {
10178 /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */
10179 res = (duk_uint32_t) (0);
10180 n = 6;
10181 } else {
10182 /* 8-byte format could be:
10183 * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits]
10184 *
10185 * However, this format would not have a zero bit following the
10186 * leading one bits and would not allow 0xFF to be used as an
10187 * "invalid xutf-8" marker for internal keys. Further, 8-byte
10188 * encodings (up to 41 bit code points) are not currently needed.
10189 */
10190 goto fail;
10191 }
10192
10193 DUK_ASSERT(p >= ptr_start); /* verified at beginning */
10194 if (p + n > ptr_end) {
10195 /* check pointer at end */
10196 goto fail;
10197 }
10198
10199 while (n > 0) {
10200 DUK_ASSERT(p >= ptr_start && p < ptr_end);
10201 res = res << 6;
10202 res += (duk_uint32_t) ((*p++) & 0x3f);
10203 n--;
10204 }
10205
10206 *ptr = p;
10207 *out_cp = res;
10208 return 1;
10209
10210 fail:
10211 return 0;
10212}
10213
10214/* used by e.g. duk_regexp_executor.c, string built-ins */
10215DUK_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) {
10216 duk_ucodepoint_t cp;
10217
10218 if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
10219 return cp;
10220 }
10221 DUK_ERROR_INTERNAL(thr, "utf-8 decode failed"); /* XXX: 'internal error' is a bit of a misnomer */
10222 DUK_UNREACHABLE();
10223 return 0;
10224}
10225
10226/* Compute (extended) utf-8 length without codepoint encoding validation,
10227 * used for string interning.
10228 *
10229 * NOTE: This algorithm is performance critical, more so than string hashing
10230 * in some cases. It is needed when interning a string and needs to scan
10231 * every byte of the string with no skipping. Having an ASCII fast path
10232 * is useful if possible in the algorithm. The current algorithms were
10233 * chosen from several variants, based on x64 gcc -O2 testing. See:
10234 * https://github.com/svaarala/duktape/pull/422
10235 *
10236 * NOTE: must match src/dukutil.py:duk_unicode_unvalidated_utf8_length().
10237 */
10238
10239#if defined(DUK_USE_PREFER_SIZE)
10240/* Small variant; roughly 150 bytes smaller than the fast variant. */
10241DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
10242 const duk_uint8_t *p;
10243 const duk_uint8_t *p_end;
10244 duk_size_t ncont;
10245 duk_size_t clen;
10246
10247 p = data;
10248 p_end = data + blen;
10249 ncont = 0;
10250 while (p != p_end) {
10251 duk_uint8_t x;
10252 x = *p++;
10253 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10254 ncont++;
10255 }
10256 }
10257
10258 DUK_ASSERT(ncont <= blen);
10259 clen = blen - ncont;
10260 DUK_ASSERT(clen <= blen);
10261 return clen;
10262}
10263#else /* DUK_USE_PREFER_SIZE */
10264/* This seems like a good overall approach. Fast path for ASCII in 4 byte
10265 * blocks.
10266 */
10267DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
10268 const duk_uint8_t *p;
10269 const duk_uint8_t *p_end;
10270 const duk_uint32_t *p32_end;
10271 const duk_uint32_t *p32;
10272 duk_size_t ncont;
10273 duk_size_t clen;
10274
10275 ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */
10276 p = data;
10277 p_end = data + blen;
10278 if (blen < 16) {
10279 goto skip_fastpath;
10280 }
10281
10282 /* Align 'p' to 4; the input data may have arbitrary alignment.
10283 * End of string check not needed because blen >= 16.
10284 */
10285 while (((duk_size_t) (const void *) p) & 0x03U) {
10286 duk_uint8_t x;
10287 x = *p++;
10288 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10289 ncont++;
10290 }
10291 }
10292
10293 /* Full, aligned 4-byte reads. */
10294 p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03)));
10295 p32 = (const duk_uint32_t *) (const void *) p;
10296 while (p32 != (const duk_uint32_t *) p32_end) {
10297 duk_uint32_t x;
10298 x = *p32++;
10299 if (DUK_LIKELY((x & 0x80808080UL) == 0)) {
10300 ; /* ASCII fast path */
10301 } else {
10302 /* Flip highest bit of each byte which changes
10303 * the bit pattern 10xxxxxx into 00xxxxxx which
10304 * allows an easy bit mask test.
10305 */
10306 x ^= 0x80808080UL;
10307 if (DUK_UNLIKELY(!(x & 0xc0000000UL))) {
10308 ncont++;
10309 }
10310 if (DUK_UNLIKELY(!(x & 0x00c00000UL))) {
10311 ncont++;
10312 }
10313 if (DUK_UNLIKELY(!(x & 0x0000c000UL))) {
10314 ncont++;
10315 }
10316 if (DUK_UNLIKELY(!(x & 0x000000c0UL))) {
10317 ncont++;
10318 }
10319 }
10320 }
10321 p = (const duk_uint8_t *) p32;
10322 /* Fall through to handle the rest. */
10323
10324 skip_fastpath:
10325 while (p != p_end) {
10326 duk_uint8_t x;
10327 x = *p++;
10328 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10329 ncont++;
10330 }
10331 }
10332
10333 DUK_ASSERT(ncont <= blen);
10334 clen = blen - ncont;
10335 DUK_ASSERT(clen <= blen);
10336 return clen;
10337}
10338#endif /* DUK_USE_PREFER_SIZE */
10339
10340/*
10341 * Unicode range matcher
10342 *
10343 * Matches a codepoint against a packed bitstream of character ranges.
10344 * Used for slow path Unicode matching.
10345 */
10346
10347/* Must match src/extract_chars.py, generate_match_table3(). */
10348DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
10349 duk_uint32_t t;
10350
10351 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4);
10352 if (t <= 0x0eU) {
10353 return t;
10354 }
10355 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8);
10356 if (t <= 0xfdU) {
10357 return t + 0x0f;
10358 }
10359 if (t == 0xfeU) {
10360 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12);
10361 return t + 0x0fU + 0xfeU;
10362 } else {
10363 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24);
10364 return t + 0x0fU + 0xfeU + 0x1000UL;
10365 }
10366}
10367
10368DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) {
10369 duk_bitdecoder_ctx bd_ctx;
10370 duk_codepoint_t prev_re;
10371
10372 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
10373 bd_ctx.data = (const duk_uint8_t *) unitab;
10374 bd_ctx.length = (duk_size_t) unilen;
10375
10376 prev_re = 0;
10377 for (;;) {
10378 duk_codepoint_t r1, r2;
10379 r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
10380 if (r1 == 0) {
10381 break;
10382 }
10383 r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
10384
10385 r1 = prev_re + r1;
10386 r2 = r1 + r2;
10387 prev_re = r2;
10388
10389 /* [r1,r2] is the range */
10390
10391 DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]",
10392 (unsigned long) cp, (unsigned long) r1, (unsigned long) r2));
10393 if (cp >= r1 && cp <= r2) {
10394 return 1;
10395 }
10396 }
10397
10398 return 0;
10399}
10400
10401/*
10402 * "WhiteSpace" production check.
10403 */
10404
10405DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
10406 /*
10407 * E5 Section 7.2 specifies six characters specifically as
10408 * white space:
10409 *
10410 * 0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
10411 * 000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
10412 * 000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
10413 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
10414 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
10415 * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
10416 *
10417 * It also specifies any Unicode category 'Zs' characters as white
10418 * space. These can be extracted with the "src/extract_chars.py" script.
10419 * Current result:
10420 *
10421 * RAW OUTPUT:
10422 * ===========
10423 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
10424 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
10425 * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
10426 * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
10427 * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
10428 * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
10429 * 2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10430 * 2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10431 * 2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10432 * 2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10433 * 2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10434 * 2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
10435 * 2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10436 * 2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10437 * 200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10438 * 202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
10439 * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10440 * 3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
10441 *
10442 * RANGES:
10443 * =======
10444 * 0x0020
10445 * 0x00a0
10446 * 0x1680
10447 * 0x180e
10448 * 0x2000 ... 0x200a
10449 * 0x202f
10450 * 0x205f
10451 * 0x3000
10452 *
10453 * A manual decoder (below) is probably most compact for this.
10454 */
10455
10456 duk_uint_fast8_t lo;
10457 duk_uint_fast32_t hi;
10458
10459 /* cp == -1 (EOF) never matches and causes return value 0 */
10460
10461 lo = (duk_uint_fast8_t) (cp & 0xff);
10462 hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */
10463
10464 if (hi == 0x0000UL) {
10465 if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU ||
10466 lo == 0x20U || lo == 0xa0U) {
10467 return 1;
10468 }
10469 } else if (hi == 0x0020UL) {
10470 if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) {
10471 return 1;
10472 }
10473 } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L ||
10474 cp == 0xfeffL) {
10475 return 1;
10476 }
10477
10478 return 0;
10479}
10480
10481/*
10482 * "LineTerminator" production check.
10483 */
10484
10485DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) {
10486 /*
10487 * E5 Section 7.3
10488 *
10489 * A LineTerminatorSequence essentially merges <CR> <LF> sequences
10490 * into a single line terminator. This must be handled by the caller.
10491 */
10492
10493 if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L ||
10494 cp == 0x2029L) {
10495 return 1;
10496 }
10497
10498 return 0;
10499}
10500
10501/*
10502 * "IdentifierStart" production check.
10503 */
10504
10505DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) {
10506 /*
10507 * E5 Section 7.6:
10508 *
10509 * IdentifierStart:
10510 * UnicodeLetter
10511 * $
10512 * _
10513 * \ UnicodeEscapeSequence
10514 *
10515 * IdentifierStart production has one multi-character production:
10516 *
10517 * \ UnicodeEscapeSequence
10518 *
10519 * The '\' character is -not- matched by this function. Rather, the caller
10520 * should decode the escape and then call this function to check whether the
10521 * decoded character is acceptable (see discussion in E5 Section 7.6).
10522 *
10523 * The "UnicodeLetter" alternative of the production allows letters
10524 * from various Unicode categories. These can be extracted with the
10525 * "src/extract_chars.py" script.
10526 *
10527 * Because the result has hundreds of Unicode codepoint ranges, matching
10528 * for any values >= 0x80 are done using a very slow range-by-range scan
10529 * and a packed range format.
10530 *
10531 * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because
10532 * it matters the most. The ASCII related ranges of IdentifierStart are:
10533 *
10534 * 0x0041 ... 0x005a ['A' ... 'Z']
10535 * 0x0061 ... 0x007a ['a' ... 'z']
10536 * 0x0024 ['$']
10537 * 0x005f ['_']
10538 */
10539
10540 /* ASCII (and EOF) fast path -- quick accept and reject */
10541 if (cp <= 0x7fL) {
10542#if defined(DUK_USE_IDCHAR_FASTPATH)
10543 return (cp >= 0) && (duk_is_idchar_tab[cp] > 0);
10544#else
10545 if ((cp >= 'a' && cp <= 'z') ||
10546 (cp >= 'A' && cp <= 'Z') ||
10547 cp == '_' || cp == '$') {
10548 return 1;
10549 }
10550 return 0;
10551#endif
10552 }
10553
10554 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
10555
10556#ifdef DUK_USE_SOURCE_NONBMP
10557 if (duk__uni_range_match(duk_unicode_ids_noa,
10558 (duk_size_t) sizeof(duk_unicode_ids_noa),
10559 (duk_codepoint_t) cp)) {
10560 return 1;
10561 }
10562 return 0;
10563#else
10564 if (cp < 0x10000L) {
10565 if (duk__uni_range_match(duk_unicode_ids_noabmp,
10566 sizeof(duk_unicode_ids_noabmp),
10567 (duk_codepoint_t) cp)) {
10568 return 1;
10569 }
10570 return 0;
10571 } else {
10572 /* without explicit non-BMP support, assume non-BMP characters
10573 * are always accepted as identifier characters.
10574 */
10575 return 1;
10576 }
10577#endif
10578}
10579
10580/*
10581 * "IdentifierPart" production check.
10582 */
10583
10584DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) {
10585 /*
10586 * E5 Section 7.6:
10587 *
10588 * IdentifierPart:
10589 * IdentifierStart
10590 * UnicodeCombiningMark
10591 * UnicodeDigit
10592 * UnicodeConnectorPunctuation
10593 * <ZWNJ> [U+200C]
10594 * <ZWJ> [U+200D]
10595 *
10596 * IdentifierPart production has one multi-character production
10597 * as part of its IdentifierStart alternative. The '\' character
10598 * of an escape sequence is not matched here, see discussion in
10599 * duk_unicode_is_identifier_start().
10600 *
10601 * To match non-ASCII characters (codepoints >= 0x80), a very slow
10602 * linear range-by-range scan is used. The codepoint is first compared
10603 * to the IdentifierStart ranges, and if it doesn't match, then to a
10604 * set consisting of code points in IdentifierPart but not in
10605 * IdentifierStart. This is done to keep the unicode range data small,
10606 * at the expense of speed.
10607 *
10608 * The ASCII fast path consists of:
10609 *
10610 * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit]
10611 * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart]
10612 * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart]
10613 * 0x0024 ['$', IdentifierStart]
10614 * 0x005f ['_', IdentifierStart and
10615 * UnicodeConnectorPunctuation]
10616 *
10617 * UnicodeCombiningMark has no code points <= 0x7f.
10618 *
10619 * The matching code reuses the "identifier start" tables, and then
10620 * consults a separate range set for characters in "identifier part"
10621 * but not in "identifier start". These can be extracted with the
10622 * "src/extract_chars.py" script.
10623 *
10624 * UnicodeCombiningMark -> categories Mn, Mc
10625 * UnicodeDigit -> categories Nd
10626 * UnicodeConnectorPunctuation -> categories Pc
10627 */
10628
10629 /* ASCII (and EOF) fast path -- quick accept and reject */
10630 if (cp <= 0x7fL) {
10631#if defined(DUK_USE_IDCHAR_FASTPATH)
10632 return (cp >= 0) && (duk_is_idchar_tab[cp] != 0);
10633#else
10634 if ((cp >= 'a' && cp <= 'z') ||
10635 (cp >= 'A' && cp <= 'Z') ||
10636 (cp >= '0' && cp <= '9') ||
10637 cp == '_' || cp == '$') {
10638 return 1;
10639 }
10640 return 0;
10641#endif
10642 }
10643
10644 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
10645
10646#ifdef DUK_USE_SOURCE_NONBMP
10647 if (duk__uni_range_match(duk_unicode_ids_noa,
10648 sizeof(duk_unicode_ids_noa),
10649 (duk_codepoint_t) cp) ||
10650 duk__uni_range_match(duk_unicode_idp_m_ids_noa,
10651 sizeof(duk_unicode_idp_m_ids_noa),
10652 (duk_codepoint_t) cp)) {
10653 return 1;
10654 }
10655 return 0;
10656#else
10657 if (cp < 0x10000L) {
10658 if (duk__uni_range_match(duk_unicode_ids_noabmp,
10659 sizeof(duk_unicode_ids_noabmp),
10660 (duk_codepoint_t) cp) ||
10661 duk__uni_range_match(duk_unicode_idp_m_ids_noabmp,
10662 sizeof(duk_unicode_idp_m_ids_noabmp),
10663 (duk_codepoint_t) cp)) {
10664 return 1;
10665 }
10666 return 0;
10667 } else {
10668 /* without explicit non-BMP support, assume non-BMP characters
10669 * are always accepted as identifier characters.
10670 */
10671 return 1;
10672 }
10673#endif
10674}
10675
10676/*
10677 * Unicode letter check.
10678 */
10679
10680DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
10681 /*
10682 * Unicode letter is now taken to be the categories:
10683 *
10684 * Lu, Ll, Lt, Lm, Lo
10685 *
10686 * (Not sure if this is exactly correct.)
10687 *
10688 * The ASCII fast path consists of:
10689 *
10690 * 0x0041 ... 0x005a ['A' ... 'Z']
10691 * 0x0061 ... 0x007a ['a' ... 'z']
10692 */
10693
10694 /* ASCII (and EOF) fast path -- quick accept and reject */
10695 if (cp <= 0x7fL) {
10696 if ((cp >= 'a' && cp <= 'z') ||
10697 (cp >= 'A' && cp <= 'Z')) {
10698 return 1;
10699 }
10700 return 0;
10701 }
10702
10703 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
10704
10705#ifdef DUK_USE_SOURCE_NONBMP
10706 if (duk__uni_range_match(duk_unicode_ids_noa,
10707 sizeof(duk_unicode_ids_noa),
10708 (duk_codepoint_t) cp) &&
10709 !duk__uni_range_match(duk_unicode_ids_m_let_noa,
10710 sizeof(duk_unicode_ids_m_let_noa),
10711 (duk_codepoint_t) cp)) {
10712 return 1;
10713 }
10714 return 0;
10715#else
10716 if (cp < 0x10000L) {
10717 if (duk__uni_range_match(duk_unicode_ids_noabmp,
10718 sizeof(duk_unicode_ids_noabmp),
10719 (duk_codepoint_t) cp) &&
10720 !duk__uni_range_match(duk_unicode_ids_m_let_noabmp,
10721 sizeof(duk_unicode_ids_m_let_noabmp),
10722 (duk_codepoint_t) cp)) {
10723 return 1;
10724 }
10725 return 0;
10726 } else {
10727 /* without explicit non-BMP support, assume non-BMP characters
10728 * are always accepted as letters.
10729 */
10730 return 1;
10731 }
10732#endif
10733}
10734
10735/*
10736 * Complex case conversion helper which decodes a bit-packed conversion
10737 * control stream generated by unicode/extract_caseconv.py. The conversion
10738 * is very slow because it runs through the conversion data in a linear
10739 * fashion to save space (which is why ASCII characters have a special
10740 * fast path before arriving here).
10741 *
10742 * The particular bit counts etc have been determined experimentally to
10743 * be small but still sufficient, and must match the Python script
10744 * (src/extract_caseconv.py).
10745 *
10746 * The return value is the case converted codepoint or -1 if the conversion
10747 * results in multiple characters (this is useful for regexp Canonicalization
10748 * operation). If 'buf' is not NULL, the result codepoint(s) are also
10749 * appended to the hbuffer.
10750 *
10751 * Context and locale specific rules must be checked before consulting
10752 * this function.
10753 */
10754
10755DUK_LOCAL
10756duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
10757 duk_bufwriter_ctx *bw,
10758 duk_codepoint_t cp,
10759 duk_bitdecoder_ctx *bd_ctx) {
10760 duk_small_int_t skip = 0;
10761 duk_small_int_t n;
10762 duk_small_int_t t;
10763 duk_small_int_t count;
10764 duk_codepoint_t tmp_cp;
10765 duk_codepoint_t start_i;
10766 duk_codepoint_t start_o;
10767
10768 DUK_UNREF(thr);
10769 DUK_ASSERT(bd_ctx != NULL);
10770
10771 DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
10772
10773 /* range conversion with a "skip" */
10774 DUK_DDD(DUK_DDDPRINT("checking ranges"));
10775 for (;;) {
10776 skip++;
10777 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
10778 if (n == 0x3f) {
10779 /* end marker */
10780 break;
10781 }
10782 DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n));
10783
10784 while (n--) {
10785 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10786 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10787 count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
10788 DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld",
10789 (long) start_i, (long) start_o, (long) count, (long) skip));
10790
10791 if (cp >= start_i) {
10792 tmp_cp = cp - start_i; /* always >= 0 */
10793 if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip &&
10794 (tmp_cp % (duk_codepoint_t) skip) == 0) {
10795 DUK_DDD(DUK_DDDPRINT("range matches input codepoint"));
10796 cp = start_o + tmp_cp;
10797 goto single;
10798 }
10799 }
10800 }
10801 }
10802
10803 /* 1:1 conversion */
10804 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
10805 DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
10806 while (n--) {
10807 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10808 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10809 DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o));
10810 if (cp == start_i) {
10811 DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint"));
10812 cp = start_o;
10813 goto single;
10814 }
10815 }
10816
10817 /* complex, multicharacter conversion */
10818 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
10819 DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n));
10820 while (n--) {
10821 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10822 t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2);
10823 DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t));
10824 if (cp == start_i) {
10825 DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint"));
10826 if (bw != NULL) {
10827 while (t--) {
10828 tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10829 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp);
10830 }
10831 }
10832 return -1;
10833 } else {
10834 while (t--) {
10835 (void) duk_bd_decode(bd_ctx, 16);
10836 }
10837 }
10838 }
10839
10840 /* default: no change */
10841 DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input"));
10842 /* fall through */
10843
10844 single:
10845 if (bw != NULL) {
10846 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
10847 }
10848 return cp;
10849}
10850
10851/*
10852 * Case conversion helper, with context/local sensitivity.
10853 * For proper case conversion, one needs to know the character
10854 * and the preceding and following characters, as well as
10855 * locale/language.
10856 */
10857
10858/* XXX: add 'language' argument when locale/language sensitive rule
10859 * support added.
10860 */
10861DUK_LOCAL
10862duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
10863 duk_bufwriter_ctx *bw,
10864 duk_codepoint_t cp,
10865 duk_codepoint_t prev,
10866 duk_codepoint_t next,
10867 duk_bool_t uppercase) {
10868 duk_bitdecoder_ctx bd_ctx;
10869
10870 /* fast path for ASCII */
10871 if (cp < 0x80L) {
10872 /* XXX: there are language sensitive rules for the ASCII range.
10873 * If/when language/locale support is implemented, they need to
10874 * be implemented here for the fast path. There are no context
10875 * sensitive rules for ASCII range.
10876 */
10877
10878 if (uppercase) {
10879 if (cp >= 'a' && cp <= 'z') {
10880 cp = cp - 'a' + 'A';
10881 }
10882 } else {
10883 if (cp >= 'A' && cp <= 'Z') {
10884 cp = cp - 'A' + 'a';
10885 }
10886 }
10887
10888 if (bw != NULL) {
10889 DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp);
10890 }
10891 return cp;
10892 }
10893
10894 /* context and locale specific rules which cannot currently be represented
10895 * in the caseconv bitstream: hardcoded rules in C
10896 */
10897 if (uppercase) {
10898 /* XXX: turkish / azeri */
10899 } else {
10900 /*
10901 * Final sigma context specific rule. This is a rather tricky
10902 * rule and this handling is probably not 100% correct now.
10903 * The rule is not locale/language specific so it is supported.
10904 */
10905
10906 if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */
10907 duk_unicode_is_letter(prev) && /* prev exists and is not a letter */
10908 !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */
10909 /* Capital sigma occurred at "end of word", lowercase to
10910 * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise
10911 * fall through and let the normal rules lowercase it to
10912 * U+03C3 = GREEK SMALL LETTER SIGMA.
10913 */
10914 cp = 0x03c2L;
10915 goto singlechar;
10916 }
10917
10918 /* XXX: lithuanian not implemented */
10919 /* XXX: lithuanian, explicit dot rules */
10920 /* XXX: turkish / azeri, lowercase rules */
10921 }
10922
10923 /* 1:1 or special conversions, but not locale/context specific: script generated rules */
10924 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
10925 if (uppercase) {
10926 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
10927 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
10928 } else {
10929 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc;
10930 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
10931 }
10932 return duk__slow_case_conversion(thr, bw, cp, &bd_ctx);
10933
10934 singlechar:
10935 if (bw != NULL) {
10936 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
10937 }
10938 return cp;
10939
10940 /* unused now, not needed until Turkish/Azeri */
10941#if 0
10942 nochar:
10943 return -1;
10944#endif
10945}
10946
10947/*
10948 * Replace valstack top with case converted version.
10949 */
10950
10951DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
10952 duk_context *ctx = (duk_context *) thr;
10953 duk_hstring *h_input;
10954 duk_bufwriter_ctx bw_alloc;
10955 duk_bufwriter_ctx *bw;
10956 const duk_uint8_t *p, *p_start, *p_end;
10957 duk_codepoint_t prev, curr, next;
10958
10959 h_input = duk_require_hstring(ctx, -1);
10960 DUK_ASSERT(h_input != NULL);
10961
10962 bw = &bw_alloc;
10963 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));
10964
10965 /* [ ... input buffer ] */
10966
10967 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
10968 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
10969 p = p_start;
10970
10971 prev = -1; DUK_UNREF(prev);
10972 curr = -1;
10973 next = -1;
10974 for (;;) {
10975 prev = curr;
10976 curr = next;
10977 next = -1;
10978 if (p < p_end) {
10979 next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
10980 } else {
10981 /* end of input and last char has been processed */
10982 if (curr < 0) {
10983 break;
10984 }
10985 }
10986
10987 /* on first round, skip */
10988 if (curr >= 0) {
10989 /* XXX: could add a fast path to process chunks of input codepoints,
10990 * but relative benefit would be quite small.
10991 */
10992
10993 /* Ensure space for maximum multi-character result; estimate is overkill. */
10994 DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH);
10995
10996 duk__case_transform_helper(thr,
10997 bw,
10998 (duk_codepoint_t) curr,
10999 prev,
11000 next,
11001 uppercase);
11002 }
11003 }
11004
11005 DUK_BW_COMPACT(thr, bw);
11006 duk_to_string(ctx, -1); /* invalidates h_buf pointer */
11007 duk_remove(ctx, -2);
11008}
11009
11010#ifdef DUK_USE_REGEXP_SUPPORT
11011
11012/*
11013 * Canonicalize() abstract operation needed for canonicalization of individual
11014 * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8.
11015 * Note that codepoints are canonicalized one character at a time, so no context
11016 * specific rules can apply. Locale specific rules can apply, though.
11017 */
11018
11019DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
11020#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
11021 /* Fast canonicalization lookup at the cost of 128kB footprint. */
11022 DUK_ASSERT(cp >= 0);
11023 DUK_UNREF(thr);
11024 if (DUK_LIKELY(cp < 0x10000L)) {
11025 return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp];
11026 }
11027 return cp;
11028#else /* DUK_USE_REGEXP_CANON_WORKAROUND */
11029 duk_codepoint_t y;
11030
11031 y = duk__case_transform_helper(thr,
11032 NULL, /* NULL is allowed, no output */
11033 cp, /* curr char */
11034 -1, /* prev char */
11035 -1, /* next char */
11036 1); /* uppercase */
11037
11038 if ((y < 0) || (cp >= 0x80 && y < 0x80)) {
11039 /* multiple codepoint conversion or non-ASCII mapped to ASCII
11040 * --> leave as is.
11041 */
11042 return cp;
11043 }
11044
11045 return y;
11046#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */
11047}
11048
11049/*
11050 * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume
11051 * x < 0 for characters read outside the string.
11052 */
11053
11054DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) {
11055 /*
11056 * Note: the description in E5 Section 15.10.2.6 has a typo, it
11057 * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_].
11058 */
11059 if ((x >= '0' && x <= '9') ||
11060 (x >= 'a' && x <= 'z') ||
11061 (x >= 'A' && x <= 'Z') ||
11062 (x == '_')) {
11063 return 1;
11064 }
11065 return 0;
11066}
11067
11068/*
11069 * Regexp range tables
11070 */
11071
11072/* exposed because lexer needs these too */
11073DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = {
11074 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
11075};
11076DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = {
11077 (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL,
11078 (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL,
11079 (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL,
11080 (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL,
11081 (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL,
11082 (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL,
11083 (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL,
11084 (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL,
11085 (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL,
11086 (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL,
11087 (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL,
11088};
11089DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = {
11090 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
11091 (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL,
11092 (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL,
11093 (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL,
11094};
11095DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = {
11096 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
11097 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL,
11098};
11099DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = {
11100 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL,
11101 (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL,
11102 (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL,
11103 (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL,
11104 (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL,
11105 (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL,
11106 (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL,
11107 (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL,
11108 (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL,
11109 (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL,
11110 (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL,
11111 (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL,
11112};
11113DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
11114 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
11115 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL,
11116 (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL,
11117 (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL,
11118 (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL,
11119};
11120
11121#endif /* DUK_USE_REGEXP_SUPPORT */
11122#line 1 "duk_util_misc.c"
11123/*
11124 * Misc util stuff
11125 */
11126
11127/* include removed: duk_internal.h */
11128
11129/*
11130 * Lowercase digits for radix values 2 to 36. Also doubles as lowercase
11131 * hex nybble table.
11132 */
11133
11134DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = {
11135 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
11136 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
11137 DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B,
11138 DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F,
11139 DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J,
11140 DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N,
11141 DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R,
11142 DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V,
11143 DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z
11144};
11145
11146DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = {
11147 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
11148 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
11149 DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B,
11150 DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F
11151};
11152
11153/*
11154 * Table for hex decoding ASCII hex digits
11155 */
11156
11157DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = {
11158 /* -1 if invalid */
11159 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
11160 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
11161 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
11162 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
11163 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
11164 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
11165 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
11166 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
11167 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
11168 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
11169 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
11170 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
11171 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
11172 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
11173 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
11174 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
11175};
11176
11177#if defined(DUK_USE_HEX_FASTPATH)
11178/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */
11179DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = {
11180 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
11181 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
11182 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
11183 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
11184 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
11185 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
11186 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
11187 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
11188 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
11189 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
11190 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
11191 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
11192 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
11193 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
11194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
11195 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
11196};
11197#endif
11198
11199/*
11200 * Table for hex encoding bytes
11201 */
11202
11203#if defined(DUK_USE_HEX_FASTPATH)
11204/* Lookup to encode one byte directly into 2 characters:
11205 *
11206 * def genhextab(bswap):
11207 * for i in xrange(256):
11208 * t = chr(i).encode('hex')
11209 * if bswap:
11210 * t = t[1] + t[0]
11211 * print('0x' + t.encode('hex') + 'U')
11212 * print('big endian'); genhextab(False)
11213 * print('little endian'); genhextab(True)
11214*/
11215DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
11216#if defined(DUK_USE_INTEGER_BE)
11217 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U,
11218 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U,
11219 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U,
11220 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U,
11221 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U,
11222 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U,
11223 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U,
11224 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U,
11225 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U,
11226 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U,
11227 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U,
11228 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U,
11229 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U,
11230 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U,
11231 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U,
11232 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U,
11233 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U,
11234 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U,
11235 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U,
11236 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U,
11237 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U,
11238 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U,
11239 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U,
11240 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U,
11241 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U,
11242 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U,
11243 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U,
11244 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U,
11245 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U,
11246 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U,
11247 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U,
11248 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U
11249#else /* DUK_USE_INTEGER_BE */
11250 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U,
11251 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U,
11252 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U,
11253 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U,
11254 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U,
11255 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U,
11256 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U,
11257 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U,
11258 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U,
11259 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U,
11260 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U,
11261 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U,
11262 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U,
11263 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U,
11264 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U,
11265 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U,
11266 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U,
11267 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U,
11268 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U,
11269 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U,
11270 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U,
11271 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U,
11272 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U,
11273 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U,
11274 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U,
11275 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U,
11276 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U,
11277 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U,
11278 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U,
11279 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U,
11280 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U,
11281 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U
11282#endif /* DUK_USE_INTEGER_BE */
11283};
11284#endif /* DUK_USE_HEX_FASTPATH */
11285
11286/*
11287 * Table for base-64 encoding
11288 */
11289
11290#if defined(DUK_USE_BASE64_FASTPATH)
11291DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = {
11292 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */
11293 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */
11294 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */
11295 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */
11296};
11297#endif /* DUK_USE_BASE64_FASTPATH */
11298
11299/*
11300 * Table for base-64 decoding
11301 */
11302
11303#if defined(DUK_USE_BASE64_FASTPATH)
11304DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = {
11305 /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */
11306 -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */
11307 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */
11308 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */
11309 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */
11310 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
11311 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */
11312 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
11313 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */
11314 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */
11315 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */
11316 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */
11317 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */
11318 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */
11319 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */
11320 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */
11321 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */
11322};
11323#endif /* DUK_USE_BASE64_FASTPATH */
11324
11325/*
11326 * Arbitrary byteswap for potentially unaligned values
11327 *
11328 * Used to byteswap pointers e.g. in debugger code.
11329 */
11330
11331#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
11332DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
11333 duk_uint8_t tmp;
11334 duk_uint8_t *q = p + len - 1;
11335
11336 while (p - q < 0) {
11337 tmp = *p;
11338 *p = *q;
11339 *q = tmp;
11340 p++;
11341 q--;
11342 }
11343}
11344#endif
11345#line 1 "duk_util_hashprime.c"
11346/*
11347 * Round a number upwards to a prime (not usually the nearest one).
11348 *
11349 * Uses a table of successive 32-bit primes whose ratio is roughly
11350 * constant. This keeps the relative upwards 'rounding error' bounded
11351 * and the data size small. A simple 'predict-correct' compression is
11352 * used to compress primes to one byte per prime. See genhashsizes.py
11353 * for details.
11354 *
11355 * The minimum prime returned here must be coordinated with the possible
11356 * probe sequence steps in duk_hobject and duk_heap stringtable.
11357 */
11358
11359/* include removed: duk_internal.h */
11360
11361/* Awkward inclusion condition: drop out of compilation if not needed by any
11362 * call site: object hash part or probing stringtable.
11363 */
11364#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
11365
11366/* hash size ratio goal, must match genhashsizes.py */
11367#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */
11368
11369/* prediction corrections for prime list (see genhashsizes.py) */
11370DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = {
11371 17, /* minimum prime */
11372 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3,
11373 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5,
11374 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29,
11375 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12,
11376 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30,
11377 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41,
11378 10, 23, 16, 9, 2,
11379 -1
11380};
11381
11382/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long
11383 * (DUK_UTIL_GET_HASH_PROBE_STEP macro).
11384 */
11385DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = {
11386 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107,
11387 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199
11388};
11389
11390DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
11391 const duk_int8_t *p = duk__hash_size_corrections;
11392 duk_uint32_t curr;
11393
11394 curr = (duk_uint32_t) *p++;
11395 for (;;) {
11396 duk_small_int_t t = (duk_small_int_t) *p++;
11397 if (t < 0) {
11398 /* may happen if size is very close to 2^32-1 */
11399 break;
11400 }
11401
11402 /* prediction: portable variant using doubles if 64-bit values not available */
11403#ifdef DUK_USE_64BIT_OPS
11404 curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10);
11405#else
11406 /* 32-bit x 11-bit = 43-bit, fits accurately into a double */
11407 curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0);
11408#endif
11409
11410 /* correction */
11411 curr += t;
11412
11413 DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr));
11414
11415 if (curr >= size) {
11416 return curr;
11417 }
11418 }
11419 return 0;
11420}
11421
11422#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */
11423#line 1 "duk_hobject_class.c"
11424/*
11425 * Hobject Ecmascript [[Class]].
11426 */
11427
11428/* include removed: duk_internal.h */
11429
11430#if (DUK_STRIDX_UC_ARGUMENTS > 255)
11431#error constant too large
11432#endif
11433#if (DUK_STRIDX_ARRAY > 255)
11434#error constant too large
11435#endif
11436#if (DUK_STRIDX_UC_BOOLEAN > 255)
11437#error constant too large
11438#endif
11439#if (DUK_STRIDX_DATE > 255)
11440#error constant too large
11441#endif
11442#if (DUK_STRIDX_UC_ERROR > 255)
11443#error constant too large
11444#endif
11445#if (DUK_STRIDX_UC_FUNCTION > 255)
11446#error constant too large
11447#endif
11448#if (DUK_STRIDX_JSON > 255)
11449#error constant too large
11450#endif
11451#if (DUK_STRIDX_MATH > 255)
11452#error constant too large
11453#endif
11454#if (DUK_STRIDX_UC_NUMBER > 255)
11455#error constant too large
11456#endif
11457#if (DUK_STRIDX_UC_OBJECT > 255)
11458#error constant too large
11459#endif
11460#if (DUK_STRIDX_REG_EXP > 255)
11461#error constant too large
11462#endif
11463#if (DUK_STRIDX_UC_STRING > 255)
11464#error constant too large
11465#endif
11466#if (DUK_STRIDX_GLOBAL > 255)
11467#error constant too large
11468#endif
11469#if (DUK_STRIDX_OBJ_ENV > 255)
11470#error constant too large
11471#endif
11472#if (DUK_STRIDX_DEC_ENV > 255)
11473#error constant too large
11474#endif
11475#if (DUK_STRIDX_UC_BUFFER > 255)
11476#error constant too large
11477#endif
11478#if (DUK_STRIDX_UC_POINTER > 255)
11479#error constant too large
11480#endif
11481#if (DUK_STRIDX_UC_THREAD > 255)
11482#error constant too large
11483#endif
11484#if (DUK_STRIDX_ARRAY_BUFFER > 255)
11485#error constant too large
11486#endif
11487#if (DUK_STRIDX_DATA_VIEW > 255)
11488#error constant too large
11489#endif
11490#if (DUK_STRIDX_INT8_ARRAY > 255)
11491#error constant too large
11492#endif
11493#if (DUK_STRIDX_UINT8_ARRAY > 255)
11494#error constant too large
11495#endif
11496#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255)
11497#error constant too large
11498#endif
11499#if (DUK_STRIDX_INT16_ARRAY > 255)
11500#error constant too large
11501#endif
11502#if (DUK_STRIDX_UINT16_ARRAY > 255)
11503#error constant too large
11504#endif
11505#if (DUK_STRIDX_INT32_ARRAY > 255)
11506#error constant too large
11507#endif
11508#if (DUK_STRIDX_UINT32_ARRAY > 255)
11509#error constant too large
11510#endif
11511#if (DUK_STRIDX_FLOAT32_ARRAY > 255)
11512#error constant too large
11513#endif
11514#if (DUK_STRIDX_FLOAT64_ARRAY > 255)
11515#error constant too large
11516#endif
11517#if (DUK_STRIDX_EMPTY_STRING > 255)
11518#error constant too large
11519#endif
11520
11521/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
11522DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
11523 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
11524 DUK_STRIDX_UC_ARGUMENTS,
11525 DUK_STRIDX_ARRAY,
11526 DUK_STRIDX_UC_BOOLEAN,
11527 DUK_STRIDX_DATE,
11528 DUK_STRIDX_UC_ERROR,
11529 DUK_STRIDX_UC_FUNCTION,
11530 DUK_STRIDX_JSON,
11531 DUK_STRIDX_MATH,
11532 DUK_STRIDX_UC_NUMBER,
11533 DUK_STRIDX_UC_OBJECT,
11534 DUK_STRIDX_REG_EXP,
11535 DUK_STRIDX_UC_STRING,
11536 DUK_STRIDX_GLOBAL,
11537 DUK_STRIDX_OBJ_ENV,
11538 DUK_STRIDX_DEC_ENV,
11539 DUK_STRIDX_UC_BUFFER,
11540 DUK_STRIDX_UC_POINTER,
11541 DUK_STRIDX_UC_THREAD,
11542 DUK_STRIDX_ARRAY_BUFFER,
11543 DUK_STRIDX_DATA_VIEW,
11544 DUK_STRIDX_INT8_ARRAY,
11545 DUK_STRIDX_UINT8_ARRAY,
11546 DUK_STRIDX_UINT8_CLAMPED_ARRAY,
11547 DUK_STRIDX_INT16_ARRAY,
11548 DUK_STRIDX_UINT16_ARRAY,
11549 DUK_STRIDX_INT32_ARRAY,
11550 DUK_STRIDX_UINT32_ARRAY,
11551 DUK_STRIDX_FLOAT32_ARRAY,
11552 DUK_STRIDX_FLOAT64_ARRAY,
11553 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
11554 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
11555};
11556#line 1 "duk_alloc_default.c"
11557/*
11558 * Default allocation functions.
11559 *
11560 * Assumes behavior such as malloc allowing zero size, yielding
11561 * a NULL or a unique pointer which is a no-op for free.
11562 */
11563
11564/* include removed: duk_internal.h */
11565
11566#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
11567DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
11568 void *res;
11569 DUK_UNREF(udata);
11570 res = DUK_ANSI_MALLOC(size);
11571 DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p",
11572 (unsigned long) size, (void *) res));
11573 return res;
11574}
11575
11576DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) {
11577 void *res;
11578 DUK_UNREF(udata);
11579 res = DUK_ANSI_REALLOC(ptr, newsize);
11580 DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p",
11581 (void *) ptr, (unsigned long) newsize, (void *) res));
11582 return res;
11583}
11584
11585DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
11586 DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr));
11587 DUK_UNREF(udata);
11588 DUK_ANSI_FREE(ptr);
11589}
11590#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */
11591#line 1 "duk_api_buffer.c"
11592/*
11593 * Buffer
11594 */
11595
11596/* include removed: duk_internal.h */
11597
11598DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) {
11599 duk_hthread *thr = (duk_hthread *) ctx;
11600 duk_hbuffer_dynamic *h;
11601
11602 DUK_ASSERT_CTX_VALID(ctx);
11603
11604 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
11605 DUK_ASSERT(h != NULL);
11606
11607 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
11608 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
11609 }
11610
11611 /* maximum size check is handled by callee */
11612 duk_hbuffer_resize(thr, h, new_size);
11613
11614 return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
11615}
11616
11617DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
11618 duk_hthread *thr = (duk_hthread *) ctx;
11619 duk_hbuffer_dynamic *h;
11620 void *ptr;
11621 duk_size_t sz;
11622
11623 DUK_ASSERT(ctx != NULL);
11624
11625 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
11626 DUK_ASSERT(h != NULL);
11627
11628 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
11629 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
11630 }
11631
11632 /* Forget the previous allocation, setting size to 0 and alloc to
11633 * NULL. Caller is responsible for freeing the previous allocation.
11634 * Getting the allocation and clearing it is done in the same API
11635 * call to avoid any chance of a realloc.
11636 */
11637 ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
11638 sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
11639 if (out_size) {
11640 *out_size = sz;
11641 }
11642 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
11643 DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
11644
11645 return ptr;
11646}
11647
11648DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) {
11649 duk_hthread *thr = (duk_hthread *) ctx;
11650 duk_hbuffer_external *h;
11651
11652 DUK_ASSERT(ctx != NULL);
11653
11654 h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index);
11655 DUK_ASSERT(h != NULL);
11656
11657 if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
11658 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
11659 }
11660 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
11661
11662 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
11663 DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
11664}
11665#line 1 "duk_api_bytecode.c"
11666/*
11667 * Bytecode dump/load
11668 *
11669 * The bytecode load primitive is more important performance-wise than the
11670 * dump primitive.
11671 *
11672 * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
11673 * memory safe for invalid arguments - caller beware! There's little point
11674 * in trying to achieve memory safety unless bytecode instructions are also
11675 * validated which is not easy to do with indirect register references etc.
11676 */
11677
11678/* include removed: duk_internal.h */
11679
11680#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
11681
11682#define DUK__SER_MARKER 0xff
11683#define DUK__SER_VERSION 0x00
11684#define DUK__SER_STRING 0x00
11685#define DUK__SER_NUMBER 0x01
11686#define DUK__BYTECODE_INITIAL_ALLOC 256
11687
11688/*
11689 * Dump/load helpers, xxx_raw() helpers do no buffer checks
11690 */
11691
11692DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) {
11693 duk_uint32_t len;
11694
11695 len = DUK_RAW_READ_U32_BE(p);
11696 duk_push_lstring(ctx, (const char *) p, len);
11697 p += len;
11698 return p;
11699}
11700
11701DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) {
11702 duk_uint32_t len;
11703 duk_uint8_t *buf;
11704
11705 len = DUK_RAW_READ_U32_BE(p);
11706 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
11707 DUK_ASSERT(buf != NULL);
11708 DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
11709 p += len;
11710 return p;
11711}
11712
11713DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
11714 duk_size_t len;
11715 duk_uint32_t tmp32;
11716
11717 DUK_ASSERT(h != NULL);
11718
11719 len = DUK_HSTRING_GET_BYTELEN(h);
11720 DUK_ASSERT(len <= 0xffffffffUL); /* string limits */
11721 tmp32 = (duk_uint32_t) len;
11722 DUK_RAW_WRITE_U32_BE(p, tmp32);
11723 DUK_MEMCPY((void *) p,
11724 (const void *) DUK_HSTRING_GET_DATA(h),
11725 len);
11726 p += len;
11727 return p;
11728}
11729
11730DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) {
11731 duk_size_t len;
11732 duk_uint32_t tmp32;
11733
11734 DUK_ASSERT(thr != NULL);
11735 DUK_ASSERT(h != NULL);
11736 DUK_UNREF(thr);
11737
11738 len = DUK_HBUFFER_GET_SIZE(h);
11739 DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
11740 tmp32 = (duk_uint32_t) len;
11741 DUK_RAW_WRITE_U32_BE(p, tmp32);
11742 DUK_MEMCPY((void *) p,
11743 (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
11744 len);
11745 p += len;
11746 return p;
11747}
11748
11749DUK_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) {
11750 duk_hstring *h_str;
11751 duk_tval *tv;
11752
11753 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
11754 if (tv != NULL && DUK_TVAL_IS_STRING(tv)) {
11755 h_str = DUK_TVAL_GET_STRING(tv);
11756 DUK_ASSERT(h_str != NULL);
11757 } else {
11758 h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
11759 DUK_ASSERT(h_str != NULL);
11760 }
11761 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11762 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p);
11763 p = duk__dump_hstring_raw(p, h_str);
11764 return p;
11765}
11766
11767DUK_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) {
11768 duk_tval *tv;
11769
11770 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
11771 if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) {
11772 duk_hbuffer *h_buf;
11773 h_buf = DUK_TVAL_GET_BUFFER(tv);
11774 DUK_ASSERT(h_buf != NULL);
11775 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11776 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p);
11777 p = duk__dump_hbuffer_raw(thr, p, h_buf);
11778 } else {
11779 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11780 DUK_RAW_WRITE_U32_BE(p, 0);
11781 }
11782 return p;
11783}
11784
11785DUK_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) {
11786 duk_tval *tv;
11787 duk_uint32_t val;
11788
11789 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
11790 if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) {
11791 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
11792 } else {
11793 val = def_value;
11794 }
11795 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11796 DUK_RAW_WRITE_U32_BE(p, val);
11797 return p;
11798}
11799
11800DUK_LOCAL duk_uint8_t *duk__dump_varmap(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_VARMAP(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 _Varmap only has own properties so walk property
11812 * table directly. We also know _Varmap is dense and all
11813 * values are numbers; assert for these. GC and finalizers
11814 * shouldn't affect _Varmap so side effects should be fine.
11815 */
11816 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
11817 duk_hstring *key;
11818 duk_tval *tv_val;
11819 duk_uint32_t val;
11820
11821 key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
11822 DUK_ASSERT(key != NULL); /* _Varmap is dense */
11823 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i));
11824 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i);
11825 DUK_ASSERT(tv_val != NULL);
11826 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */
11827#if defined(DUK_USE_FASTINT)
11828 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val));
11829 DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */
11830 val = DUK_TVAL_GET_FASTINT_U32(tv_val);
11831#else
11832 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val);
11833#endif
11834
11835 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11836 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p);
11837 p = duk__dump_hstring_raw(p, key);
11838 DUK_RAW_WRITE_U32_BE(p, val);
11839 }
11840 }
11841 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11842 DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */
11843 return p;
11844}
11845
11846DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
11847 duk_tval *tv;
11848
11849 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
11850 if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
11851 duk_hobject *h;
11852 duk_uint_fast32_t i;
11853
11854 h = DUK_TVAL_GET_OBJECT(tv);
11855 DUK_ASSERT(h != NULL);
11856
11857 /* We know _Formals is dense and all entries will be in the
11858 * array part. GC and finalizers shouldn't affect _Formals
11859 * so side effects should be fine.
11860 */
11861 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
11862 duk_tval *tv_val;
11863 duk_hstring *varname;
11864
11865 tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
11866 DUK_ASSERT(tv_val != NULL);
11867 if (DUK_TVAL_IS_STRING(tv_val)) {
11868 /* Array is dense and contains only strings, but ASIZE may
11869 * be larger than used part and there are UNUSED entries.
11870 */
11871 varname = DUK_TVAL_GET_STRING(tv_val);
11872 DUK_ASSERT(varname != NULL);
11873
11874 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11875 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
11876 p = duk__dump_hstring_raw(p, varname);
11877 }
11878 }
11879 }
11880 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11881 DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
11882 return p;
11883}
11884
11885static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
11886 duk_hthread *thr;
11887 duk_tval *tv, *tv_end;
11888 duk_instr_t *ins, *ins_end;
11889 duk_hobject **fn, **fn_end;
11890 duk_hstring *h_str;
11891 duk_uint32_t count_instr;
11892 duk_uint32_t tmp32;
11893 duk_uint16_t tmp16;
11894 duk_double_t d;
11895
11896 thr = (duk_hthread *) ctx;
11897 DUK_UNREF(ctx);
11898 DUK_UNREF(thr);
11899
11900 DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
11901 "consts=[%p,%p[ (%ld bytes, %ld items), "
11902 "funcs=[%p,%p[ (%ld bytes, %ld items), "
11903 "code=[%p,%p[ (%ld bytes, %ld items)",
11904 (void *) func,
11905 (void *) p,
11906 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func),
11907 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func),
11908 (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func),
11909 (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func),
11910 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func),
11911 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func),
11912 (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func),
11913 (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func),
11914 (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func),
11915 (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func),
11916 (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func),
11917 (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func)));
11918
11919 DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
11920 count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func);
11921 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p);
11922
11923 /* Fixed header info. */
11924 tmp32 = count_instr;
11925 DUK_RAW_WRITE_U32_BE(p, tmp32);
11926 tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func);
11927 DUK_RAW_WRITE_U32_BE(p, tmp32);
11928 tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func);
11929 DUK_RAW_WRITE_U32_BE(p, tmp32);
11930 tmp16 = func->nregs;
11931 DUK_RAW_WRITE_U16_BE(p, tmp16);
11932 tmp16 = func->nargs;
11933 DUK_RAW_WRITE_U16_BE(p, tmp16);
11934#if defined(DUK_USE_DEBUGGER_SUPPORT)
11935 tmp32 = func->start_line;
11936 DUK_RAW_WRITE_U32_BE(p, tmp32);
11937 tmp32 = func->end_line;
11938 DUK_RAW_WRITE_U32_BE(p, tmp32);
11939#else
11940 DUK_RAW_WRITE_U32_BE(p, 0);
11941 DUK_RAW_WRITE_U32_BE(p, 0);
11942#endif
11943 tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK;
11944 DUK_RAW_WRITE_U32_BE(p, tmp32);
11945
11946 /* Bytecode instructions: endian conversion needed unless
11947 * platform is big endian.
11948 */
11949 ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func);
11950 ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func);
11951 DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
11952#if defined(DUK_USE_INTEGER_BE)
11953 DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins));
11954 p += (size_t) (ins_end - ins);
11955#else
11956 while (ins != ins_end) {
11957 tmp32 = (duk_uint32_t) (*ins);
11958 DUK_RAW_WRITE_U32_BE(p, tmp32);
11959 ins++;
11960 }
11961#endif
11962
11963 /* Constants: variable size encoding. */
11964 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func);
11965 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func);
11966 while (tv != tv_end) {
11967 /* constants are strings or numbers now */
11968 DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
11969 DUK_TVAL_IS_NUMBER(tv));
11970
11971 if (DUK_TVAL_IS_STRING(tv)) {
11972 h_str = DUK_TVAL_GET_STRING(tv);
11973 DUK_ASSERT(h_str != NULL);
11974 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11975 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p),
11976 *p++ = DUK__SER_STRING;
11977 p = duk__dump_hstring_raw(p, h_str);
11978 } else {
11979 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
11980 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p);
11981 *p++ = DUK__SER_NUMBER;
11982 d = DUK_TVAL_GET_NUMBER(tv);
11983 DUK_RAW_WRITE_DOUBLE_BE(p, d);
11984 }
11985 tv++;
11986 }
11987
11988 /* Inner functions recursively. */
11989 fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func);
11990 fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func);
11991 while (fn != fn_end) {
11992 /* XXX: This causes recursion up to inner function depth
11993 * which is normally not an issue, e.g. mark-and-sweep uses
11994 * a recursion limiter to avoid C stack issues. Avoiding
11995 * this would mean some sort of a work list or just refusing
11996 * to serialize deep functions.
11997 */
11998 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn));
11999 p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p);
12000 fn++;
12001 }
12002
12003 /* Object extra properties.
12004 *
12005 * There are some difference between function templates and functions.
12006 * For example, function templates don't have .length and nargs is
12007 * normally used to instantiate the functions.
12008 */
12009
12010 p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
12011 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
12012 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
12013 p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
12014 p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
12015 p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
12016
12017 DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p));
12018
12019 return p;
12020}
12021
12022/* Load a function from bytecode. The function object returned here must
12023 * match what is created by duk_js_push_closure() with respect to its flags,
12024 * properties, etc.
12025 *
12026 * NOTE: there are intentionally no input buffer length / bound checks.
12027 * Adding them would be easy but wouldn't ensure memory safety as untrusted
12028 * or broken bytecode is unsafe during execution unless the opcodes themselves
12029 * are validated (which is quite complex, especially for indirect opcodes).
12030 */
12031
12032#define DUK__ASSERT_LEFT(n) do { \
12033 DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
12034 } while (0)
12035
12036static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) {
12037 duk_hthread *thr;
12038 duk_hcompiledfunction *h_fun;
12039 duk_hbuffer *h_data;
12040 duk_size_t data_size;
12041 duk_uint32_t count_instr, count_const, count_funcs;
12042 duk_uint32_t n;
12043 duk_uint32_t tmp32;
12044 duk_small_uint_t const_type;
12045 duk_uint8_t *fun_data;
12046 duk_uint8_t *q;
12047 duk_idx_t idx_base;
12048 duk_tval *tv1;
12049 duk_uarridx_t arr_idx;
12050
12051 /* XXX: There's some overlap with duk_js_closure() here, but
12052 * seems difficult to share code. Ensure that the final function
12053 * looks the same as created by duk_js_closure().
12054 */
12055
12056 DUK_ASSERT(ctx != NULL);
12057 thr = (duk_hthread *) ctx;
12058
12059 DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
12060
12061 DUK__ASSERT_LEFT(3 * 4);
12062 count_instr = DUK_RAW_READ_U32_BE(p);
12063 count_const = DUK_RAW_READ_U32_BE(p);
12064 count_funcs = DUK_RAW_READ_U32_BE(p);
12065
12066 data_size = sizeof(duk_tval) * count_const +
12067 sizeof(duk_hobject *) * count_funcs +
12068 sizeof(duk_instr_t) * count_instr;
12069
12070 DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
12071 (long) count_instr, (long) count_const,
12072 (long) count_const, (long) data_size));
12073
12074 /* Value stack is used to ensure reachability of constants and
12075 * inner functions being loaded. Require enough space to handle
12076 * large functions correctly.
12077 */
12078 duk_require_stack(ctx, 2 + count_const + count_funcs);
12079 idx_base = duk_get_top(ctx);
12080
12081 /* Push function object, init flags etc. This must match
12082 * duk_js_push_closure() quite carefully.
12083 */
12084 duk_push_compiledfunction(ctx);
12085 h_fun = duk_get_hcompiledfunction(ctx, -1);
12086 DUK_ASSERT(h_fun != NULL);
12087 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun));
12088 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL);
12089 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL);
12090 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL);
12091
12092 h_fun->nregs = DUK_RAW_READ_U16_BE(p);
12093 h_fun->nargs = DUK_RAW_READ_U16_BE(p);
12094#if defined(DUK_USE_DEBUGGER_SUPPORT)
12095 h_fun->start_line = DUK_RAW_READ_U32_BE(p);
12096 h_fun->end_line = DUK_RAW_READ_U32_BE(p);
12097#else
12098 p += 8; /* skip line info */
12099#endif
12100
12101 /* duk_hcompiledfunction flags; quite version specific */
12102 tmp32 = DUK_RAW_READ_U32_BE(p);
12103 DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32);
12104
12105 /* standard prototype */
12106 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
12107
12108 /* assert just a few critical flags */
12109 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
12110 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj));
12111 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj));
12112 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj));
12113 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj));
12114 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
12115 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
12116 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
12117
12118 /* Create function 'data' buffer but don't attach it yet. */
12119 fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size);
12120 DUK_ASSERT(fun_data != NULL);
12121
12122 /* Load bytecode instructions. */
12123 DUK_ASSERT(sizeof(duk_instr_t) == 4);
12124 DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
12125#if defined(DUK_USE_INTEGER_BE)
12126 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
12127 DUK_MEMCPY((void *) q,
12128 (const void *) p,
12129 sizeof(duk_instr_t) * count_instr);
12130 p += sizeof(duk_instr_t) * count_instr;
12131#else
12132 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
12133 for (n = count_instr; n > 0; n--) {
12134 *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p);
12135 q += sizeof(duk_instr_t);
12136 }
12137#endif
12138
12139 /* Load constants onto value stack but don't yet copy to buffer. */
12140 for (n = count_const; n > 0; n--) {
12141 DUK__ASSERT_LEFT(1);
12142 const_type = DUK_RAW_READ_U8(p);
12143 switch (const_type) {
12144 case DUK__SER_STRING: {
12145 p = duk__load_string_raw(ctx, p);
12146 break;
12147 }
12148 case DUK__SER_NUMBER: {
12149 /* Important to do a fastint check so that constants are
12150 * properly read back as fastints.
12151 */
12152 duk_tval tv_tmp;
12153 duk_double_t val;
12154 DUK__ASSERT_LEFT(8);
12155 val = DUK_RAW_READ_DOUBLE_BE(p);
12156 DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val);
12157 duk_push_tval(ctx, &tv_tmp);
12158 break;
12159 }
12160 default: {
12161 goto format_error;
12162 }
12163 }
12164 }
12165
12166 /* Load inner functions to value stack, but don't yet copy to buffer. */
12167 for (n = count_funcs; n > 0; n--) {
12168 p = duk__load_func(ctx, p, p_end);
12169 if (p == NULL) {
12170 goto format_error;
12171 }
12172 }
12173
12174 /* With constants and inner functions on value stack, we can now
12175 * atomically finish the function 'data' buffer, bump refcounts,
12176 * etc.
12177 *
12178 * Here we take advantage of the value stack being just a duk_tval
12179 * array: we can just memcpy() the constants as long as we incref
12180 * them afterwards.
12181 */
12182
12183 h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1);
12184 DUK_ASSERT(h_data != NULL);
12185 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
12186 DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data);
12187 DUK_HBUFFER_INCREF(thr, h_data);
12188
12189 tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */
12190 DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
12191
12192 q = fun_data;
12193 if (count_const > 0) {
12194 /* Explicit zero size check to avoid NULL 'tv1'. */
12195 DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
12196 for (n = count_const; n > 0; n--) {
12197 DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
12198 q += sizeof(duk_tval);
12199 }
12200 tv1 += count_const;
12201 }
12202
12203 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
12204 for (n = count_funcs; n > 0; n--) {
12205 duk_hobject *h_obj;
12206
12207 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
12208 h_obj = DUK_TVAL_GET_OBJECT(tv1);
12209 DUK_ASSERT(h_obj != NULL);
12210 tv1++;
12211 DUK_HOBJECT_INCREF(thr, h_obj);
12212
12213 *((duk_hobject **) (void *) q) = h_obj;
12214 q += sizeof(duk_hobject *);
12215 }
12216
12217 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
12218
12219 /* The function object is now reachable and refcounts are fine,
12220 * so we can pop off all the temporaries.
12221 */
12222 DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base)));
12223 duk_set_top(ctx, idx_base + 1);
12224
12225 /* Setup function properties. */
12226 tmp32 = DUK_RAW_READ_U32_BE(p);
12227 duk_push_u32(ctx, tmp32);
12228 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
12229
12230 p = duk__load_string_raw(ctx, p);
12231 if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
12232 /* Original function instance/template had NAMEBINDING.
12233 * Must create a lexical environment on loading to allow
12234 * recursive functions like 'function foo() { foo(); }'.
12235 */
12236 duk_hobject *proto;
12237
12238 proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
12239 (void) duk_push_object_helper_proto(ctx,
12240 DUK_HOBJECT_FLAG_EXTENSIBLE |
12241 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
12242 proto);
12243 duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */
12244 duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */
12245 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
12246 duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
12247 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
12248 * will be ignored anyway
12249 */
12250 }
12251 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
12252
12253 p = duk__load_string_raw(ctx, p);
12254 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
12255
12256 duk_push_object(ctx);
12257 duk_dup(ctx, -2);
12258 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
12259 duk_compact(ctx, -1);
12260 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
12261
12262 p = duk__load_buffer_raw(ctx, p);
12263 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
12264
12265 duk_push_object(ctx); /* _Varmap */
12266 for (;;) {
12267 /* XXX: awkward */
12268 p = duk__load_string_raw(ctx, p);
12269 if (duk_get_length(ctx, -1) == 0) {
12270 duk_pop(ctx);
12271 break;
12272 }
12273 tmp32 = DUK_RAW_READ_U32_BE(p);
12274 duk_push_u32(ctx, tmp32);
12275 duk_put_prop(ctx, -3);
12276 }
12277 duk_compact(ctx, -1);
12278 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
12279
12280 duk_push_array(ctx); /* _Formals */
12281 for (arr_idx = 0; ; arr_idx++) {
12282 /* XXX: awkward */
12283 p = duk__load_string_raw(ctx, p);
12284 if (duk_get_length(ctx, -1) == 0) {
12285 duk_pop(ctx);
12286 break;
12287 }
12288 duk_put_prop_index(ctx, -2, arr_idx);
12289 }
12290 duk_compact(ctx, -1);
12291 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
12292
12293 /* Return with final function pushed on stack top. */
12294 DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1)));
12295 DUK_ASSERT_TOP(ctx, idx_base + 1);
12296 return p;
12297
12298 format_error:
12299 return NULL;
12300}
12301
12302DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
12303 duk_hthread *thr;
12304 duk_hcompiledfunction *func;
12305 duk_bufwriter_ctx bw_ctx_alloc;
12306 duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
12307 duk_uint8_t *p;
12308
12309 DUK_ASSERT(ctx != NULL);
12310 thr = (duk_hthread *) ctx;
12311
12312 /* Bound functions don't have all properties so we'd either need to
12313 * lookup the non-bound target function or reject bound functions.
12314 * For now, bound functions are rejected.
12315 */
12316 func = duk_require_hcompiledfunction(ctx, -1);
12317 DUK_ASSERT(func != NULL);
12318 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj));
12319
12320 /* Estimating the result size beforehand would be costly, so
12321 * start with a reasonable size and extend as needed.
12322 */
12323 DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
12324 p = DUK_BW_GET_PTR(thr, bw_ctx);
12325 *p++ = DUK__SER_MARKER;
12326 *p++ = DUK__SER_VERSION;
12327 p = duk__dump_func(ctx, func, bw_ctx, p);
12328 DUK_BW_SET_PTR(thr, bw_ctx, p);
12329 DUK_BW_COMPACT(thr, bw_ctx);
12330
12331 DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1)));
12332
12333 duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */
12334}
12335
12336DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
12337 duk_hthread *thr;
12338 duk_uint8_t *p_buf, *p, *p_end;
12339 duk_size_t sz;
12340
12341 DUK_ASSERT(ctx != NULL);
12342 thr = (duk_hthread *) ctx;
12343 DUK_UNREF(ctx);
12344
12345 p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
12346 DUK_ASSERT(p_buf != NULL);
12347
12348 /* The caller is responsible for being sure that bytecode being loaded
12349 * is valid and trusted. Invalid bytecode can cause memory unsafe
12350 * behavior directly during loading or later during bytecode execution
12351 * (instruction validation would be quite complex to implement).
12352 *
12353 * This signature check is the only sanity check for detecting
12354 * accidental invalid inputs. The initial 0xFF byte ensures no
12355 * ordinary string will be accepted by accident.
12356 */
12357 p = p_buf;
12358 p_end = p_buf + sz;
12359 if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
12360 goto format_error;
12361 }
12362 p += 2;
12363
12364 p = duk__load_func(ctx, p, p_end);
12365 if (p == NULL) {
12366 goto format_error;
12367 }
12368
12369 duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */
12370 return;
12371
12372 format_error:
12373 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
12374}
12375
12376#undef DUK__SER_MARKER
12377#undef DUK__SER_VERSION
12378#undef DUK__SER_STRING
12379#undef DUK__SER_NUMBER
12380#undef DUK__BYTECODE_INITIAL_ALLOC
12381
12382#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
12383
12384DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
12385 DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
12386}
12387
12388DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
12389 DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
12390}
12391
12392#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
12393#line 1 "duk_api_call.c"
12394/*
12395 * Calls.
12396 *
12397 * Protected variants should avoid ever throwing an error.
12398 */
12399
12400/* include removed: duk_internal.h */
12401
12402/* Prepare value stack for a method call through an object property.
12403 * May currently throw an error e.g. when getting the property.
12404 */
12405DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) {
12406 DUK_ASSERT_CTX_VALID(ctx);
12407
12408 DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld",
12409 (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx)));
12410
12411 /* [... key arg1 ... argN] */
12412
12413 /* duplicate key */
12414 duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
12415 duk_get_prop(ctx, normalized_obj_index);
12416
12417 DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
12418
12419 /* [... key arg1 ... argN func] */
12420
12421 duk_replace(ctx, -nargs - 2);
12422
12423 /* [... func arg1 ... argN] */
12424
12425 duk_dup(ctx, normalized_obj_index);
12426 duk_insert(ctx, -nargs - 1);
12427
12428 /* [... func this arg1 ... argN] */
12429}
12430
12431DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
12432 duk_hthread *thr = (duk_hthread *) ctx;
12433 duk_small_uint_t call_flags;
12434 duk_idx_t idx_func;
12435
12436 DUK_ASSERT_CTX_VALID(ctx);
12437 DUK_ASSERT(thr != NULL);
12438
12439 idx_func = duk_get_top(ctx) - nargs - 1;
12440 if (idx_func < 0 || nargs < 0) {
12441 /* note that we can't reliably pop anything here */
12442 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
12443 }
12444
12445 /* XXX: awkward; we assume there is space for this, overwrite
12446 * directly instead?
12447 */
12448 duk_push_undefined(ctx);
12449 duk_insert(ctx, idx_func + 1);
12450
12451 call_flags = 0; /* not protected, respect reclimit, not constructor */
12452
12453 duk_handle_call_unprotected(thr, /* thread */
12454 nargs, /* num_stack_args */
12455 call_flags); /* call_flags */
12456}
12457
12458DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
12459 duk_hthread *thr = (duk_hthread *) ctx;
12460 duk_small_uint_t call_flags;
12461 duk_idx_t idx_func;
12462
12463 DUK_ASSERT_CTX_VALID(ctx);
12464 DUK_ASSERT(thr != NULL);
12465
12466 idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
12467 if (idx_func < 0 || nargs < 0) {
12468 /* note that we can't reliably pop anything here */
12469 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
12470 }
12471
12472 call_flags = 0; /* not protected, respect reclimit, not constructor */
12473
12474 duk_handle_call_unprotected(thr, /* thread */
12475 nargs, /* num_stack_args */
12476 call_flags); /* call_flags */
12477}
12478
12479DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
12480 /*
12481 * XXX: if duk_handle_call() took values through indices, this could be
12482 * made much more sensible. However, duk_handle_call() needs to fudge
12483 * the 'this' and 'func' values to handle bound function chains, which
12484 * is now done "in-place", so this is not a trivial change.
12485 */
12486
12487 DUK_ASSERT_CTX_VALID(ctx);
12488
12489 obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
12490 if (DUK_UNLIKELY(nargs < 0)) {
12491 DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
12492 }
12493
12494 duk__call_prop_prep_stack(ctx, obj_index, nargs);
12495
12496 duk_call_method(ctx, nargs);
12497}
12498
12499DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
12500 duk_hthread *thr = (duk_hthread *) ctx;
12501 duk_small_uint_t call_flags;
12502 duk_idx_t idx_func;
12503 duk_int_t rc;
12504
12505 DUK_ASSERT_CTX_VALID(ctx);
12506 DUK_ASSERT(thr != NULL);
12507
12508 idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */
12509 if (idx_func < 0 || nargs < 0) {
12510 /* We can't reliably pop anything here because the stack input
12511 * shape is incorrect. So we throw an error; if the caller has
12512 * no catch point for this, a fatal error will occur. Another
12513 * alternative would be to just return an error. But then the
12514 * stack would be in an unknown state which might cause some
12515 * very hard to diagnose problems later on. Also note that even
12516 * if we did not throw an error here, the underlying call handler
12517 * might STILL throw an out-of-memory error or some other internal
12518 * fatal error.
12519 */
12520 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
12521 return DUK_EXEC_ERROR; /* unreachable */
12522 }
12523
12524 /* awkward; we assume there is space for this */
12525 duk_push_undefined(ctx);
12526 duk_insert(ctx, idx_func + 1);
12527
12528 call_flags = 0; /* respect reclimit, not constructor */
12529
12530 rc = duk_handle_call_protected(thr, /* thread */
12531 nargs, /* num_stack_args */
12532 call_flags); /* call_flags */
12533
12534 return rc;
12535}
12536
12537DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
12538 duk_hthread *thr = (duk_hthread *) ctx;
12539 duk_small_uint_t call_flags;
12540 duk_idx_t idx_func;
12541 duk_int_t rc;
12542
12543 DUK_ASSERT_CTX_VALID(ctx);
12544 DUK_ASSERT(thr != NULL);
12545
12546 idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
12547 if (idx_func < 0 || nargs < 0) {
12548 /* See comments in duk_pcall(). */
12549 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
12550 return DUK_EXEC_ERROR; /* unreachable */
12551 }
12552
12553 call_flags = 0; /* respect reclimit, not constructor */
12554
12555 rc = duk_handle_call_protected(thr, /* thread */
12556 nargs, /* num_stack_args */
12557 call_flags); /* call_flags */
12558
12559 return rc;
12560}
12561
12562DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) {
12563 duk_idx_t obj_index;
12564 duk_idx_t nargs;
12565
12566 /* Get the original arguments. Note that obj_index may be a relative
12567 * index so the stack must have the same top when we use it.
12568 */
12569
12570 DUK_ASSERT_CTX_VALID(ctx);
12571
12572 obj_index = (duk_idx_t) duk_get_int(ctx, -2);
12573 nargs = (duk_idx_t) duk_get_int(ctx, -1);
12574 duk_pop_2(ctx);
12575
12576 obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
12577 duk__call_prop_prep_stack(ctx, obj_index, nargs);
12578 duk_call_method(ctx, nargs);
12579 return 1;
12580}
12581
12582DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
12583 /*
12584 * Must be careful to catch errors related to value stack manipulation
12585 * and property lookup, not just the call itself.
12586 */
12587
12588 DUK_ASSERT_CTX_VALID(ctx);
12589
12590 duk_push_idx(ctx, obj_index);
12591 if (DUK_UNLIKELY(nargs < 0)) {
12592 DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
12593 }
12594 duk_push_idx(ctx, nargs);
12595
12596 /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing.
12597 * If the value stack does not contain enough args, an error is thrown; this matches
12598 * behavior of the other protected call API functions.
12599 */
12600 return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/);
12601}
12602
12603DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) {
12604 duk_hthread *thr = (duk_hthread *) ctx;
12605 duk_int_t rc;
12606
12607 DUK_ASSERT_CTX_VALID(ctx);
12608 DUK_ASSERT(thr != NULL);
12609
12610 if (duk_get_top(ctx) < nargs || nargs < 0 || nrets < 0) {
12611 /* See comments in duk_pcall(). */
12612 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
12613 return DUK_EXEC_ERROR; /* unreachable */
12614 }
12615
12616 rc = duk_handle_safe_call(thr, /* thread */
12617 func, /* func */
12618 nargs, /* num_stack_args */
12619 nrets); /* num_stack_res */
12620
12621 return rc;
12622}
12623
12624DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
12625 /*
12626 * There are two [[Construct]] operations in the specification:
12627 *
12628 * - E5 Section 13.2.2: for Function objects
12629 * - E5 Section 15.3.4.5.2: for "bound" Function objects
12630 *
12631 * The chain of bound functions is resolved in Section 15.3.4.5.2,
12632 * with arguments "piling up" until the [[Construct]] internal
12633 * method is called on the final, actual Function object. Note
12634 * that the "prototype" property is looked up *only* from the
12635 * final object, *before* calling the constructor.
12636 *
12637 * Currently we follow the bound function chain here to get the
12638 * "prototype" property value from the final, non-bound function.
12639 * However, we let duk_handle_call() handle the argument "piling"
12640 * when the constructor is called. The bound function chain is
12641 * thus now processed twice.
12642 *
12643 * When constructing new Array instances, an unnecessary object is
12644 * created and discarded now: the standard [[Construct]] creates an
12645 * object, and calls the Array constructor. The Array constructor
12646 * returns an Array instance, which is used as the result value for
12647 * the "new" operation; the object created before the Array constructor
12648 * call is discarded.
12649 *
12650 * This would be easy to fix, e.g. by knowing that the Array constructor
12651 * will always create a replacement object and skip creating the fallback
12652 * object in that case.
12653 *
12654 * Note: functions called via "new" need to know they are called as a
12655 * constructor. For instance, built-in constructors behave differently
12656 * depending on how they are called.
12657 */
12658
12659 /* XXX: merge this with duk_js_call.c, as this function implements
12660 * core semantics (or perhaps merge the two files altogether).
12661 */
12662
12663 duk_hthread *thr = (duk_hthread *) ctx;
12664 duk_hobject *proto;
12665 duk_hobject *cons;
12666 duk_hobject *fallback;
12667 duk_idx_t idx_cons;
12668 duk_small_uint_t call_flags;
12669
12670 DUK_ASSERT_CTX_VALID(ctx);
12671
12672 /* [... constructor arg1 ... argN] */
12673
12674 idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
12675
12676 DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
12677 (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));
12678
12679 /* XXX: code duplication */
12680
12681 /*
12682 * Figure out the final, non-bound constructor, to get "prototype"
12683 * property.
12684 */
12685
12686 duk_dup(ctx, idx_cons);
12687 for (;;) {
12688 duk_tval *tv;
12689 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
12690 DUK_ASSERT(tv != NULL);
12691
12692 if (DUK_TVAL_IS_OBJECT(tv)) {
12693 cons = DUK_TVAL_GET_OBJECT(tv);
12694 DUK_ASSERT(cons != NULL);
12695 if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
12696 /* Checking callability of the immediate target
12697 * is important, same for constructability.
12698 * Checking it for functions down the bound
12699 * function chain is not strictly necessary
12700 * because .bind() should normally reject them.
12701 * But it's good to check anyway because it's
12702 * technically possible to edit the bound function
12703 * chain via internal keys.
12704 */
12705 goto not_constructable;
12706 }
12707 if (!DUK_HOBJECT_HAS_BOUND(cons)) {
12708 break;
12709 }
12710 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
12711 /* Lightfuncs cannot be bound. */
12712 break;
12713 } else {
12714 /* Anything else is not constructable. */
12715 goto not_constructable;
12716 }
12717 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */
12718 duk_remove(ctx, -2); /* -> [... target] */
12719 }
12720 DUK_ASSERT(duk_is_callable(ctx, -1));
12721 DUK_ASSERT(duk_is_lightfunc(ctx, -1) ||
12722 (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUND(duk_get_hobject(ctx, -1))));
12723
12724 /* [... constructor arg1 ... argN final_cons] */
12725
12726 /*
12727 * Create "fallback" object to be used as the object instance,
12728 * unless the constructor returns a replacement value.
12729 * Its internal prototype needs to be set based on "prototype"
12730 * property of the constructor.
12731 */
12732
12733 duk_push_object(ctx); /* class Object, extensible */
12734
12735 /* [... constructor arg1 ... argN final_cons fallback] */
12736
12737 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE);
12738 proto = duk_get_hobject(ctx, -1);
12739 if (!proto) {
12740 DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
12741 "-> leave standard Object prototype as fallback prototype"));
12742 } else {
12743 DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
12744 "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
12745 fallback = duk_get_hobject(ctx, -2);
12746 DUK_ASSERT(fallback != NULL);
12747 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
12748 }
12749 duk_pop(ctx);
12750
12751 /* [... constructor arg1 ... argN final_cons fallback] */
12752
12753 /*
12754 * Manipulate callstack for the call.
12755 */
12756
12757 duk_dup_top(ctx);
12758 duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */
12759 duk_insert(ctx, idx_cons); /* also stash it before constructor,
12760 * in case we need it (as the fallback value)
12761 */
12762 duk_pop(ctx); /* pop final_cons */
12763
12764
12765 /* [... fallback constructor fallback(this) arg1 ... argN];
12766 * Note: idx_cons points to first 'fallback', not 'constructor'.
12767 */
12768
12769 DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
12770 "nargs=%ld, top=%ld",
12771 (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
12772 (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
12773 (long) nargs,
12774 (long) duk_get_top(ctx)));
12775
12776 /*
12777 * Call the constructor function (called in "constructor mode").
12778 */
12779
12780 call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
12781
12782 duk_handle_call_unprotected(thr, /* thread */
12783 nargs, /* num_stack_args */
12784 call_flags); /* call_flags */
12785
12786 /* [... fallback retval] */
12787
12788 DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
12789 (duk_tval *) duk_get_tval(ctx, -2),
12790 (duk_tval *) duk_get_tval(ctx, -1)));
12791
12792 /*
12793 * Determine whether to use the constructor return value as the created
12794 * object instance or not.
12795 */
12796
12797 if (duk_is_object(ctx, -1)) {
12798 duk_remove(ctx, -2);
12799 } else {
12800 duk_pop(ctx);
12801 }
12802
12803 /*
12804 * Augment created errors upon creation (not when they are thrown or
12805 * rethrown). __FILE__ and __LINE__ are not desirable here; the call
12806 * stack reflects the caller which is correct.
12807 */
12808
12809#ifdef DUK_USE_AUGMENT_ERROR_CREATE
12810 duk_hthread_sync_currpc(thr);
12811 duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
12812#endif
12813
12814 /* [... retval] */
12815
12816 return;
12817
12818 not_constructable:
12819 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
12820}
12821
12822DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) {
12823 duk_uint_t nargs;
12824
12825 nargs = duk_to_uint(ctx, -1);
12826 duk_pop(ctx);
12827
12828 duk_new(ctx, nargs);
12829 return 1;
12830}
12831
12832DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
12833 duk_int_t rc;
12834
12835 DUK_ASSERT_CTX_VALID(ctx);
12836
12837 /* For now, just use duk_safe_call() to wrap duk_new(). We can't
12838 * simply use a protected duk_handle_call() because there's post
12839 * processing which might throw. It should be possible to ensure
12840 * the post processing never throws (except in internal errors and
12841 * out of memory etc which are always allowed) and then remove this
12842 * wrapper.
12843 */
12844
12845 if (DUK_UNLIKELY(nargs < 0)) {
12846 DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
12847 }
12848 duk_push_uint(ctx, nargs);
12849 rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/);
12850 return rc;
12851}
12852
12853DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
12854 duk_hthread *thr = (duk_hthread *) ctx;
12855 duk_activation *act;
12856
12857 DUK_ASSERT_CTX_VALID(ctx);
12858 DUK_ASSERT(thr != NULL);
12859 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
12860
12861 act = duk_hthread_get_current_activation(thr);
12862 if (act != NULL) {
12863 return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
12864 }
12865 return 0;
12866}
12867
12868DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
12869 duk_hthread *thr = (duk_hthread *) ctx;
12870 duk_activation *act;
12871
12872 /* For user code this could just return 1 (strict) always
12873 * because all Duktape/C functions are considered strict,
12874 * and strict is also the default when nothing is running.
12875 * However, Duktape may call this function internally when
12876 * the current activation is an Ecmascript function, so
12877 * this cannot be replaced by a 'return 1' without fixing
12878 * the internal call sites.
12879 */
12880
12881 DUK_ASSERT_CTX_VALID(ctx);
12882 DUK_ASSERT(thr != NULL);
12883 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
12884
12885 act = duk_hthread_get_current_activation(thr);
12886 if (act == NULL) {
12887 /* Strict by default. */
12888 return 1;
12889 }
12890 return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
12891}
12892
12893/*
12894 * Duktape/C function magic
12895 */
12896
12897DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
12898 duk_hthread *thr = (duk_hthread *) ctx;
12899 duk_activation *act;
12900 duk_hobject *func;
12901
12902 DUK_ASSERT_CTX_VALID(ctx);
12903 DUK_ASSERT(thr != NULL);
12904 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
12905
12906 act = duk_hthread_get_current_activation(thr);
12907 if (act) {
12908 func = DUK_ACT_GET_FUNC(act);
12909 if (!func) {
12910 duk_tval *tv = &act->tv_func;
12911 duk_small_uint_t lf_flags;
12912 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
12913 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
12914 }
12915 DUK_ASSERT(func != NULL);
12916
12917 if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
12918 duk_hnativefunction *nf = (duk_hnativefunction *) func;
12919 return (duk_int_t) nf->magic;
12920 }
12921 }
12922 return 0;
12923}
12924
12925DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
12926 duk_hthread *thr = (duk_hthread *) ctx;
12927 duk_tval *tv;
12928 duk_hobject *h;
12929
12930 DUK_ASSERT_CTX_VALID(ctx);
12931
12932 tv = duk_require_tval(ctx, index);
12933 if (DUK_TVAL_IS_OBJECT(tv)) {
12934 h = DUK_TVAL_GET_OBJECT(tv);
12935 DUK_ASSERT(h != NULL);
12936 if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
12937 goto type_error;
12938 }
12939 return (duk_int_t) ((duk_hnativefunction *) h)->magic;
12940 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
12941 duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
12942 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
12943 }
12944
12945 /* fall through */
12946 type_error:
12947 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
12948 return 0;
12949}
12950
12951DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) {
12952 duk_hnativefunction *nf;
12953
12954 DUK_ASSERT_CTX_VALID(ctx);
12955
12956 nf = duk_require_hnativefunction(ctx, index);
12957 DUK_ASSERT(nf != NULL);
12958 nf->magic = (duk_int16_t) magic;
12959}
12960#line 1 "duk_api_codec.c"
12961/*
12962 * Encoding and decoding basic formats: hex, base64.
12963 *
12964 * These are in-place operations which may allow an optimized implementation.
12965 *
12966 * Base-64: https://tools.ietf.org/html/rfc4648#section-4
12967 */
12968
12969/* include removed: duk_internal.h */
12970
12971/* Shared handling for encode/decode argument. Fast path handling for
12972 * buffer and string values because they're the most common. In particular,
12973 * avoid creating a temporary string or buffer when possible.
12974 */
12975DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
12976 DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */
12977 if (duk_is_buffer(ctx, index)) {
12978 return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len);
12979 } else {
12980 return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len);
12981 }
12982}
12983
12984#if defined(DUK_USE_BASE64_FASTPATH)
12985DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
12986 duk_uint_t t;
12987 duk_size_t n_full, n_full3, n_final;
12988 const duk_uint8_t *src_end_fast;
12989
12990 n_full = srclen / 3; /* full 3-byte -> 4-char conversions */
12991 n_full3 = n_full * 3;
12992 n_final = srclen - n_full3;
12993 DUK_ASSERT_DISABLE(n_final >= 0);
12994 DUK_ASSERT(n_final <= 2);
12995
12996 src_end_fast = src + n_full3;
12997 while (DUK_UNLIKELY(src != src_end_fast)) {
12998 t = (duk_uint_t) (*src++);
12999 t = (t << 8) + (duk_uint_t) (*src++);
13000 t = (t << 8) + (duk_uint_t) (*src++);
13001
13002 *dst++ = duk_base64_enctab[t >> 18];
13003 *dst++ = duk_base64_enctab[(t >> 12) & 0x3f];
13004 *dst++ = duk_base64_enctab[(t >> 6) & 0x3f];
13005 *dst++ = duk_base64_enctab[t & 0x3f];
13006
13007#if 0 /* Tested: not faster on x64 */
13008 /* aaaaaabb bbbbcccc ccdddddd */
13009 dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f];
13010 dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)];
13011 dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)];
13012 dst[3] = duk_base64_enctab[src[2] & 0x3f];
13013 src += 3; dst += 4;
13014#endif
13015 }
13016
13017 switch (n_final) {
13018 /* case 0: nop */
13019 case 1: {
13020 /* XX== */
13021 t = (duk_uint_t) (*src++);
13022 *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */
13023 *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */
13024 *dst++ = DUK_ASC_EQUALS;
13025 *dst++ = DUK_ASC_EQUALS;
13026 break;
13027 }
13028 case 2: {
13029 /* XXX= */
13030 t = (duk_uint_t) (*src++);
13031 t = (t << 8) + (duk_uint_t) (*src++);
13032 *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */
13033 *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */
13034 *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */
13035 *dst++ = DUK_ASC_EQUALS;
13036 break;
13037 }
13038 }
13039}
13040#else /* DUK_USE_BASE64_FASTPATH */
13041DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
13042 duk_small_uint_t i, snip;
13043 duk_uint_t t;
13044 duk_uint_fast8_t x, y;
13045 const duk_uint8_t *src_end;
13046
13047 src_end = src + srclen;
13048
13049 while (src < src_end) {
13050 /* read 3 bytes into 't', padded by zero */
13051 snip = 4;
13052 t = 0;
13053 for (i = 0; i < 3; i++) {
13054 t = t << 8;
13055 if (src >= src_end) {
13056 snip--;
13057 } else {
13058 t += (duk_uint_t) (*src++);
13059 }
13060 }
13061
13062 /*
13063 * Missing bytes snip base64 example
13064 * 0 4 XXXX
13065 * 1 3 XXX=
13066 * 2 2 XX==
13067 */
13068
13069 DUK_ASSERT(snip >= 2 && snip <= 4);
13070
13071 for (i = 0; i < 4; i++) {
13072 x = (duk_uint_fast8_t) ((t >> 18) & 0x3f);
13073 t = t << 6;
13074
13075 /* A straightforward 64-byte lookup would be faster
13076 * and cleaner, but this is shorter.
13077 */
13078 if (i >= snip) {
13079 y = '=';
13080 } else if (x <= 25) {
13081 y = x + 'A';
13082 } else if (x <= 51) {
13083 y = x - 26 + 'a';
13084 } else if (x <= 61) {
13085 y = x - 52 + '0';
13086 } else if (x == 62) {
13087 y = '+';
13088 } else {
13089 y = '/';
13090 }
13091
13092 *dst++ = (duk_uint8_t) y;
13093 }
13094 }
13095}
13096#endif /* DUK_USE_BASE64_FASTPATH */
13097
13098#if defined(DUK_USE_BASE64_FASTPATH)
13099DUK_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) {
13100 duk_int_t x;
13101 duk_int_t t;
13102 duk_small_uint_t n_equal;
13103 duk_small_uint_t n_chars;
13104 const duk_uint8_t *src_end;
13105 const duk_uint8_t *src_end_safe;
13106
13107 src_end = src + srclen;
13108 src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */
13109
13110 /* Innermost fast path processes 4 valid base-64 characters at a time
13111 * but bails out on whitespace, padding chars ('=') and invalid chars.
13112 * Once the slow path segment has been processed, we return to the
13113 * inner fast path again. This handles e.g. base64 with newlines
13114 * reasonably well because the majority of a line is in the fast path.
13115 */
13116 for (;;) {
13117 /* Fast path, handle units with just actual encoding characters. */
13118
13119 while (src <= src_end_safe) {
13120 /* The lookup byte is intentionally sign extended to (at least)
13121 * 32 bits and then ORed. This ensures that is at least 1 byte
13122 * is negative, the highest bit of 't' will be set at the end
13123 * and we don't need to check every byte.
13124 */
13125 DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p",
13126 (const void *) src, (const void *) src_end_safe, (const void *) src_end));
13127
13128 t = (duk_int_t) duk_base64_dectab[*src++];
13129 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
13130 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
13131 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
13132
13133 if (DUK_UNLIKELY(t < 0)) {
13134 DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit"));
13135 src -= 4;
13136 break;
13137 }
13138
13139 DUK_ASSERT(t <= 0xffffffL);
13140 DUK_ASSERT((t >> 24) == 0);
13141 *dst++ = (duk_uint8_t) (t >> 16);
13142 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
13143 *dst++ = (duk_uint8_t) (t & 0xff);
13144 }
13145
13146 /* Handle one slow path unit (or finish if we're done). */
13147
13148 n_equal = 0;
13149 n_chars = 0;
13150 t = 0;
13151 for (;;) {
13152 DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld",
13153 (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t));
13154
13155 if (DUK_UNLIKELY(src >= src_end)) {
13156 goto done; /* two level break */
13157 }
13158
13159 x = duk_base64_dectab[*src++];
13160 if (DUK_UNLIKELY(x < 0)) {
13161 if (x == -2) {
13162 continue; /* allowed ascii whitespace */
13163 } else if (x == -3) {
13164 n_equal++;
13165 t <<= 6;
13166 } else {
13167 DUK_ASSERT(x == -1);
13168 goto error;
13169 }
13170 } else {
13171 DUK_ASSERT(x >= 0 && x <= 63);
13172 if (n_equal > 0) {
13173 /* Don't allow actual chars after equal sign. */
13174 goto error;
13175 }
13176 t = (t << 6) + x;
13177 }
13178
13179 if (DUK_UNLIKELY(n_chars == 3)) {
13180 /* Emit 3 bytes and backtrack if there was padding. There's
13181 * always space for the whole 3 bytes so no check needed.
13182 */
13183 DUK_ASSERT(t <= 0xffffffL);
13184 DUK_ASSERT((t >> 24) == 0);
13185 *dst++ = (duk_uint8_t) (t >> 16);
13186 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
13187 *dst++ = (duk_uint8_t) (t & 0xff);
13188
13189 if (DUK_UNLIKELY(n_equal > 0)) {
13190 DUK_ASSERT(n_equal <= 4);
13191
13192 /* There may be whitespace between the equal signs. */
13193 if (n_equal == 1) {
13194 /* XXX= */
13195 dst -= 1;
13196 } else if (n_equal == 2) {
13197 /* XX== */
13198 dst -= 2;
13199 } else {
13200 goto error; /* invalid padding */
13201 }
13202
13203 /* Continue parsing after padding, allows concatenated,
13204 * padded base64.
13205 */
13206 }
13207 break; /* back to fast loop */
13208 } else {
13209 n_chars++;
13210 }
13211 }
13212 }
13213 done:
13214 DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld",
13215 (const void *) src, (const void *) src_end, (long) n_chars));
13216
13217 DUK_ASSERT(src == src_end);
13218
13219 if (n_chars != 0) {
13220 /* Here we'd have the option of decoding unpadded base64
13221 * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
13222 * accepted.
13223 */
13224 goto error;
13225 }
13226
13227 *out_dst_final = dst;
13228 return 1;
13229
13230 error:
13231 return 0;
13232}
13233#else /* DUK_USE_BASE64_FASTPATH */
13234DUK_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) {
13235 duk_uint_t t;
13236 duk_uint_fast8_t x, y;
13237 duk_small_uint_t group_idx;
13238 duk_small_uint_t n_equal;
13239 const duk_uint8_t *src_end;
13240
13241 src_end = src + srclen;
13242 t = 0;
13243 group_idx = 0;
13244 n_equal = 0;
13245
13246 while (src < src_end) {
13247 x = *src++;
13248
13249 if (x >= 'A' && x <= 'Z') {
13250 y = x - 'A' + 0;
13251 } else if (x >= 'a' && x <= 'z') {
13252 y = x - 'a' + 26;
13253 } else if (x >= '0' && x <= '9') {
13254 y = x - '0' + 52;
13255 } else if (x == '+') {
13256 y = 62;
13257 } else if (x == '/') {
13258 y = 63;
13259 } else if (x == '=') {
13260 /* We don't check the zero padding bytes here right now
13261 * (that they're actually zero). This seems to be common
13262 * behavior for base-64 decoders.
13263 */
13264
13265 n_equal++;
13266 t <<= 6; /* shift in zeroes */
13267 goto skip_add;
13268 } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) {
13269 /* allow basic ASCII whitespace */
13270 continue;
13271 } else {
13272 goto error;
13273 }
13274
13275 if (n_equal > 0) {
13276 /* Don't allow mixed padding and actual chars. */
13277 goto error;
13278 }
13279 t = (t << 6) + y;
13280 skip_add:
13281
13282 if (group_idx == 3) {
13283 /* output 3 bytes from 't' */
13284 *dst++ = (duk_uint8_t) ((t >> 16) & 0xff);
13285 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
13286 *dst++ = (duk_uint8_t) (t & 0xff);
13287
13288 if (DUK_UNLIKELY(n_equal > 0)) {
13289 /* Backtrack. */
13290 DUK_ASSERT(n_equal <= 4);
13291 if (n_equal == 1) {
13292 dst -= 1;
13293 } else if (n_equal == 2) {
13294 dst -= 2;
13295 } else {
13296 goto error; /* invalid padding */
13297 }
13298
13299 /* Here we can choose either to end parsing and ignore
13300 * whatever follows, or to continue parsing in case
13301 * multiple (possibly padded) base64 strings have been
13302 * concatenated. Currently, keep on parsing.
13303 */
13304 n_equal = 0;
13305 }
13306
13307 t = 0;
13308 group_idx = 0;
13309 } else {
13310 group_idx++;
13311 }
13312 }
13313
13314 if (group_idx != 0) {
13315 /* Here we'd have the option of decoding unpadded base64
13316 * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
13317 * accepted.
13318 */
13319 goto error;
13320 }
13321
13322 *out_dst_final = dst;
13323 return 1;
13324
13325 error:
13326 return 0;
13327}
13328#endif /* DUK_USE_BASE64_FASTPATH */
13329
13330DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
13331 duk_hthread *thr = (duk_hthread *) ctx;
13332 const duk_uint8_t *src;
13333 duk_size_t srclen;
13334 duk_size_t dstlen;
13335 duk_uint8_t *dst;
13336 const char *ret;
13337
13338 DUK_ASSERT_CTX_VALID(ctx);
13339
13340 /* XXX: optimize for string inputs: no need to coerce to a buffer
13341 * which makes a copy of the input.
13342 */
13343
13344 index = duk_require_normalize_index(ctx, index);
13345 src = duk__prep_codec_arg(ctx, index, &srclen);
13346 /* Note: for srclen=0, src may be NULL */
13347
13348 /* Computation must not wrap; this limit works for 32-bit size_t:
13349 * >>> srclen = 3221225469
13350 * >>> '%x' % ((srclen + 2) / 3 * 4)
13351 * 'fffffffc'
13352 */
13353 if (srclen > 3221225469UL) {
13354 goto type_error;
13355 }
13356 dstlen = (srclen + 2) / 3 * 4;
13357 dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen);
13358
13359 duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
13360
13361 ret = duk_to_string(ctx, -1);
13362 duk_replace(ctx, index);
13363 return ret;
13364
13365 type_error:
13366 DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED);
13367 return NULL; /* never here */
13368}
13369
13370DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
13371 duk_hthread *thr = (duk_hthread *) ctx;
13372 const duk_uint8_t *src;
13373 duk_size_t srclen;
13374 duk_size_t dstlen;
13375 duk_uint8_t *dst;
13376 duk_uint8_t *dst_final;
13377 duk_bool_t retval;
13378
13379 DUK_ASSERT_CTX_VALID(ctx);
13380
13381 /* XXX: optimize for buffer inputs: no need to coerce to a string
13382 * which causes an unnecessary interning.
13383 */
13384
13385 index = duk_require_normalize_index(ctx, index);
13386 src = duk__prep_codec_arg(ctx, index, &srclen);
13387
13388 /* Computation must not wrap, only srclen + 3 is at risk of
13389 * wrapping because after that the number gets smaller.
13390 * This limit works for 32-bit size_t:
13391 * 0x100000000 - 3 - 1 = 4294967292
13392 */
13393 if (srclen > 4294967292UL) {
13394 goto type_error;
13395 }
13396 dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
13397 dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
13398 /* Note: for dstlen=0, dst may be NULL */
13399
13400 retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
13401 if (!retval) {
13402 goto type_error;
13403 }
13404
13405 /* XXX: convert to fixed buffer? */
13406 (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst));
13407 duk_replace(ctx, index);
13408 return;
13409
13410 type_error:
13411 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
13412}
13413
13414DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
13415 const duk_uint8_t *inp;
13416 duk_size_t len;
13417 duk_size_t i;
13418 duk_uint8_t *buf;
13419 const char *ret;
13420#if defined(DUK_USE_HEX_FASTPATH)
13421 duk_size_t len_safe;
13422 duk_uint16_t *p16;
13423#endif
13424
13425 DUK_ASSERT_CTX_VALID(ctx);
13426
13427 index = duk_require_normalize_index(ctx, index);
13428 inp = duk__prep_codec_arg(ctx, index, &len);
13429 DUK_ASSERT(inp != NULL || len == 0);
13430
13431 /* Fixed buffer, no zeroing because we'll fill all the data. */
13432 buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/);
13433 DUK_ASSERT(buf != NULL);
13434
13435#if defined(DUK_USE_HEX_FASTPATH)
13436 DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */
13437 p16 = (duk_uint16_t *) (void *) buf;
13438 len_safe = len & ~0x03U;
13439 for (i = 0; i < len_safe; i += 4) {
13440 p16[0] = duk_hex_enctab[inp[i]];
13441 p16[1] = duk_hex_enctab[inp[i + 1]];
13442 p16[2] = duk_hex_enctab[inp[i + 2]];
13443 p16[3] = duk_hex_enctab[inp[i + 3]];
13444 p16 += 4;
13445 }
13446 for (; i < len; i++) {
13447 *p16++ = duk_hex_enctab[inp[i]];
13448 }
13449#else /* DUK_USE_HEX_FASTPATH */
13450 for (i = 0; i < len; i++) {
13451 duk_small_uint_t t;
13452 t = (duk_small_uint_t) inp[i];
13453 buf[i*2 + 0] = duk_lc_digits[t >> 4];
13454 buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
13455 }
13456#endif /* DUK_USE_HEX_FASTPATH */
13457
13458 /* XXX: Using a string return value forces a string intern which is
13459 * not always necessary. As a rough performance measure, hex encode
13460 * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s
13461 * without string coercion. Change to returning a buffer and let the
13462 * caller coerce to string if necessary?
13463 */
13464
13465 ret = duk_to_string(ctx, -1);
13466 duk_replace(ctx, index);
13467 return ret;
13468}
13469
13470DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
13471 duk_hthread *thr = (duk_hthread *) ctx;
13472 const duk_uint8_t *inp;
13473 duk_size_t len;
13474 duk_size_t i;
13475 duk_int_t t;
13476 duk_uint8_t *buf;
13477#if defined(DUK_USE_HEX_FASTPATH)
13478 duk_int_t chk;
13479 duk_uint8_t *p;
13480 duk_size_t len_safe;
13481#endif
13482
13483 DUK_ASSERT_CTX_VALID(ctx);
13484
13485 index = duk_require_normalize_index(ctx, index);
13486 inp = duk__prep_codec_arg(ctx, index, &len);
13487 DUK_ASSERT(inp != NULL || len == 0);
13488
13489 if (len & 0x01) {
13490 goto type_error;
13491 }
13492
13493 /* Fixed buffer, no zeroing because we'll fill all the data. */
13494 buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/);
13495 DUK_ASSERT(buf != NULL);
13496
13497#if defined(DUK_USE_HEX_FASTPATH)
13498 p = buf;
13499 len_safe = len & ~0x07U;
13500 for (i = 0; i < len_safe; i += 8) {
13501 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
13502 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
13503 chk = t;
13504 p[0] = (duk_uint8_t) t;
13505 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
13506 ((duk_int_t) duk_hex_dectab[inp[i + 3]]);
13507 chk |= t;
13508 p[1] = (duk_uint8_t) t;
13509 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
13510 ((duk_int_t) duk_hex_dectab[inp[i + 5]]);
13511 chk |= t;
13512 p[2] = (duk_uint8_t) t;
13513 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
13514 ((duk_int_t) duk_hex_dectab[inp[i + 7]]);
13515 chk |= t;
13516 p[3] = (duk_uint8_t) t;
13517 p += 4;
13518
13519 /* Check if any lookup above had a negative result. */
13520 if (DUK_UNLIKELY(chk < 0)) {
13521 goto type_error;
13522 }
13523 }
13524 for (; i < len; i += 2) {
13525 t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
13526 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
13527 if (DUK_UNLIKELY(t < 0)) {
13528 goto type_error;
13529 }
13530 *p++ = (duk_uint8_t) t;
13531 }
13532#else /* DUK_USE_HEX_FASTPATH */
13533 for (i = 0; i < len; i += 2) {
13534 /* For invalid characters the value -1 gets extended to
13535 * at least 16 bits. If either nybble is invalid, the
13536 * resulting 't' will be < 0.
13537 */
13538 t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
13539 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
13540 if (DUK_UNLIKELY(t < 0)) {
13541 goto type_error;
13542 }
13543 buf[i >> 1] = (duk_uint8_t) t;
13544 }
13545#endif /* DUK_USE_HEX_FASTPATH */
13546
13547 duk_replace(ctx, index);
13548 return;
13549
13550 type_error:
13551 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
13552}
13553
13554DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) {
13555#ifdef DUK_USE_ASSERTIONS
13556 duk_idx_t top_at_entry;
13557#endif
13558 const char *ret;
13559
13560 DUK_ASSERT_CTX_VALID(ctx);
13561#ifdef DUK_USE_ASSERTIONS
13562 top_at_entry = duk_get_top(ctx);
13563#endif
13564
13565 index = duk_require_normalize_index(ctx, index);
13566 duk_bi_json_stringify_helper(ctx,
13567 index /*idx_value*/,
13568 DUK_INVALID_INDEX /*idx_replacer*/,
13569 DUK_INVALID_INDEX /*idx_space*/,
13570 0 /*flags*/);
13571 DUK_ASSERT(duk_is_string(ctx, -1));
13572 duk_replace(ctx, index);
13573 ret = duk_get_string(ctx, index);
13574
13575 DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
13576
13577 return ret;
13578}
13579
13580DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) {
13581#ifdef DUK_USE_ASSERTIONS
13582 duk_idx_t top_at_entry;
13583#endif
13584
13585 DUK_ASSERT_CTX_VALID(ctx);
13586#ifdef DUK_USE_ASSERTIONS
13587 top_at_entry = duk_get_top(ctx);
13588#endif
13589
13590 index = duk_require_normalize_index(ctx, index);
13591 duk_bi_json_parse_helper(ctx,
13592 index /*idx_value*/,
13593 DUK_INVALID_INDEX /*idx_reviver*/,
13594 0 /*flags*/);
13595 duk_replace(ctx, index);
13596
13597 DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
13598}
13599#line 1 "duk_api_compile.c"
13600/*
13601 * Compilation and evaluation
13602 */
13603
13604/* include removed: duk_internal.h */
13605
13606typedef struct duk__compile_raw_args duk__compile_raw_args;
13607struct duk__compile_raw_args {
13608 duk_size_t src_length; /* should be first on 64-bit platforms */
13609 const duk_uint8_t *src_buffer;
13610 duk_uint_t flags;
13611};
13612
13613/* Eval is just a wrapper now. */
13614DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
13615 duk_uint_t comp_flags;
13616 duk_int_t rc;
13617
13618 DUK_ASSERT_CTX_VALID(ctx);
13619
13620 /* Note: strictness is *not* inherited from the current Duktape/C.
13621 * This would be confusing because the current strictness state
13622 * depends on whether we're running inside a Duktape/C activation
13623 * (= strict mode) or outside of any activation (= non-strict mode).
13624 * See tests/api/test-eval-strictness.c for more discussion.
13625 */
13626
13627 /* [ ... source? filename? ] (depends on flags) */
13628
13629 comp_flags = flags;
13630 comp_flags |= DUK_COMPILE_EVAL;
13631 rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */
13632
13633 /* [ ... closure/error ] */
13634
13635 if (rc != DUK_EXEC_SUCCESS) {
13636 rc = DUK_EXEC_ERROR;
13637 goto got_rc;
13638 }
13639
13640 duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */
13641
13642 if (flags & DUK_COMPILE_SAFE) {
13643 rc = duk_pcall_method(ctx, 0);
13644 } else {
13645 duk_call_method(ctx, 0);
13646 rc = DUK_EXEC_SUCCESS;
13647 }
13648
13649 /* [ ... result/error ] */
13650
13651 got_rc:
13652 if (flags & DUK_COMPILE_NORESULT) {
13653 duk_pop(ctx);
13654 }
13655
13656 return rc;
13657}
13658
13659/* Helper which can be called both directly and with duk_safe_call(). */
13660DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
13661 duk_hthread *thr = (duk_hthread *) ctx;
13662 duk__compile_raw_args *comp_args;
13663 duk_uint_t flags;
13664 duk_small_uint_t comp_flags;
13665 duk_hcompiledfunction *h_templ;
13666
13667 DUK_ASSERT_CTX_VALID(ctx);
13668
13669 /* Note: strictness is not inherited from the current Duktape/C
13670 * context. Otherwise it would not be possible to compile
13671 * non-strict code inside a Duktape/C activation (which is
13672 * always strict now). See tests/api/test-eval-strictness.c
13673 * for discussion.
13674 */
13675
13676 /* [ ... source? filename? &comp_args ] (depends on flags) */
13677
13678 comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1);
13679 flags = comp_args->flags;
13680 duk_pop(ctx);
13681
13682 /* [ ... source? filename? ] */
13683
13684 if (flags & DUK_COMPILE_NOFILENAME) {
13685 /* Automatic filename: 'eval' or 'input'. */
13686 duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
13687 }
13688
13689 /* [ ... source? filename ] */
13690
13691 if (!comp_args->src_buffer) {
13692 duk_hstring *h_sourcecode;
13693
13694 h_sourcecode = duk_get_hstring(ctx, -2);
13695 if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
13696 (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
13697 /* XXX: when this error is caused by a nonexistent
13698 * file given to duk_peval_file() or similar, the
13699 * error message is not the best possible.
13700 */
13701 DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE);
13702 }
13703 DUK_ASSERT(h_sourcecode != NULL);
13704 comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
13705 comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
13706 }
13707 DUK_ASSERT(comp_args->src_buffer != NULL);
13708
13709 /* XXX: unnecessary translation of flags */
13710 comp_flags = 0;
13711 if (flags & DUK_COMPILE_EVAL) {
13712 comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
13713 }
13714 if (flags & DUK_COMPILE_FUNCTION) {
13715 comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
13716 DUK_JS_COMPILE_FLAG_FUNCEXPR;
13717 }
13718 if (flags & DUK_COMPILE_STRICT) {
13719 comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
13720 }
13721
13722 /* [ ... source? filename ] */
13723
13724 duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);
13725
13726 /* [ ... source? func_template ] */
13727
13728 if (flags & DUK_COMPILE_NOSOURCE) {
13729 ;
13730 } else {
13731 duk_remove(ctx, -2);
13732 }
13733
13734 /* [ ... func_template ] */
13735
13736 h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
13737 DUK_ASSERT(h_templ != NULL);
13738 duk_js_push_closure(thr,
13739 h_templ,
13740 thr->builtins[DUK_BIDX_GLOBAL_ENV],
13741 thr->builtins[DUK_BIDX_GLOBAL_ENV],
13742 1 /*add_auto_proto*/);
13743 duk_remove(ctx, -2); /* -> [ ... closure ] */
13744
13745 /* [ ... closure ] */
13746
13747 return 1;
13748}
13749
13750DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
13751 duk__compile_raw_args comp_args_alloc;
13752 duk__compile_raw_args *comp_args = &comp_args_alloc;
13753
13754 DUK_ASSERT_CTX_VALID(ctx);
13755
13756 if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
13757 /* String length is computed here to avoid multiple evaluation
13758 * of a macro argument in the calling side.
13759 */
13760 src_length = DUK_STRLEN(src_buffer);
13761 }
13762
13763 comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
13764 comp_args->src_length = src_length;
13765 comp_args->flags = flags;
13766 duk_push_pointer(ctx, (void *) comp_args);
13767
13768 /* [ ... source? filename? &comp_args ] (depends on flags) */
13769
13770 if (flags & DUK_COMPILE_SAFE) {
13771 duk_int_t rc;
13772 duk_int_t nargs;
13773 duk_int_t nrets = 1;
13774
13775 /* Arguments can be: [ source? filename? &comp_args] so that
13776 * nargs is 1 to 3. Call site encodes the correct nargs count
13777 * directly into flags.
13778 */
13779 nargs = flags & 0x07;
13780 DUK_ASSERT(nargs == (1 +
13781 ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
13782 ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)));
13783 rc = duk_safe_call(ctx, duk__do_compile, nargs, nrets);
13784
13785 /* [ ... closure ] */
13786 return rc;
13787 }
13788
13789 (void) duk__do_compile(ctx);
13790
13791 /* [ ... closure ] */
13792 return DUK_EXEC_SUCCESS;
13793}
13794#line 1 "duk_api_debug.c"
13795/*
13796 * Debugging related API calls
13797 */
13798
13799/* include removed: duk_internal.h */
13800
13801DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
13802 duk_idx_t idx;
13803 duk_idx_t top;
13804
13805 DUK_ASSERT_CTX_VALID(ctx);
13806
13807 /* We don't duk_require_stack() here now, but rely on the caller having
13808 * enough space.
13809 */
13810
13811 top = duk_get_top(ctx);
13812 duk_push_array(ctx);
13813 for (idx = 0; idx < top; idx++) {
13814 duk_dup(ctx, idx);
13815 duk_put_prop_index(ctx, -2, idx);
13816 }
13817
13818 /* XXX: conversion errors should not propagate outwards.
13819 * Perhaps values need to be coerced individually?
13820 */
13821 duk_bi_json_stringify_helper(ctx,
13822 duk_get_top_index(ctx), /*idx_value*/
13823 DUK_INVALID_INDEX, /*idx_replacer*/
13824 DUK_INVALID_INDEX, /*idx_space*/
13825 DUK_JSON_FLAG_EXT_CUSTOM |
13826 DUK_JSON_FLAG_ASCII_ONLY |
13827 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
13828
13829 duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1));
13830 duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
13831 duk_pop(ctx);
13832 DUK_ASSERT(duk_is_string(ctx, -1));
13833}
13834
13835#if defined(DUK_USE_DEBUGGER_SUPPORT)
13836
13837DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
13838 duk_debug_read_function read_cb,
13839 duk_debug_write_function write_cb,
13840 duk_debug_peek_function peek_cb,
13841 duk_debug_read_flush_function read_flush_cb,
13842 duk_debug_write_flush_function write_flush_cb,
13843 duk_debug_request_function request_cb,
13844 duk_debug_detached_function detached_cb,
13845 void *udata) {
13846 duk_hthread *thr = (duk_hthread *) ctx;
13847 duk_heap *heap;
13848 const char *str;
13849 duk_size_t len;
13850
13851 /* XXX: should there be an error or an automatic detach if
13852 * already attached?
13853 */
13854
13855 DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
13856
13857 DUK_ASSERT_CTX_VALID(ctx);
13858 DUK_ASSERT(read_cb != NULL);
13859 DUK_ASSERT(write_cb != NULL);
13860 /* Other callbacks are optional. */
13861
13862 heap = thr->heap;
13863 heap->dbg_read_cb = read_cb;
13864 heap->dbg_write_cb = write_cb;
13865 heap->dbg_peek_cb = peek_cb;
13866 heap->dbg_read_flush_cb = read_flush_cb;
13867 heap->dbg_write_flush_cb = write_flush_cb;
13868 heap->dbg_request_cb = request_cb;
13869 heap->dbg_detached_cb = detached_cb;
13870 heap->dbg_udata = udata;
13871 heap->dbg_have_next_byte = 0;
13872
13873 /* Start in paused state. */
13874 heap->dbg_processing = 0;
13875 heap->dbg_paused = 1;
13876 heap->dbg_state_dirty = 1;
13877 heap->dbg_force_restart = 0;
13878 heap->dbg_step_type = 0;
13879 heap->dbg_step_thread = NULL;
13880 heap->dbg_step_csindex = 0;
13881 heap->dbg_step_startline = 0;
13882 heap->dbg_exec_counter = 0;
13883 heap->dbg_last_counter = 0;
13884 heap->dbg_last_time = 0.0;
13885
13886 /* Send version identification and flush right afterwards. Note that
13887 * we must write raw, unframed bytes here.
13888 */
13889 duk_push_sprintf(ctx, "%ld %ld %s %s\n",
13890 (long) DUK_DEBUG_PROTOCOL_VERSION,
13891 (long) DUK_VERSION,
13892 (const char *) DUK_GIT_DESCRIBE,
13893 (const char *) DUK_USE_TARGET_INFO);
13894 str = duk_get_lstring(ctx, -1, &len);
13895 DUK_ASSERT(str != NULL);
13896 duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
13897 duk_debug_write_flush(thr);
13898 duk_pop(ctx);
13899}
13900
13901DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
13902 duk_hthread *thr;
13903
13904 DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
13905
13906 DUK_ASSERT_CTX_VALID(ctx);
13907 thr = (duk_hthread *) ctx;
13908 DUK_ASSERT(thr != NULL);
13909 DUK_ASSERT(thr->heap != NULL);
13910
13911 /* Can be called multiple times with no harm. */
13912 duk_debug_do_detach(thr->heap);
13913}
13914
13915DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
13916 duk_hthread *thr;
13917 duk_bool_t processed_messages;
13918
13919 DUK_ASSERT_CTX_VALID(ctx);
13920 thr = (duk_hthread *) ctx;
13921 DUK_ASSERT(thr != NULL);
13922 DUK_ASSERT(thr->heap != NULL);
13923
13924 if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13925 return;
13926 }
13927 if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
13928 /* Calling duk_debugger_cooperate() while Duktape is being
13929 * called into is not supported. This is not a 100% check
13930 * but prevents any damage in most cases.
13931 */
13932 return;
13933 }
13934
13935 processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
13936 DUK_UNREF(processed_messages);
13937}
13938
13939DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
13940 duk_hthread *thr;
13941 duk_idx_t top;
13942 duk_idx_t idx;
13943 duk_bool_t ret = 0;
13944
13945 DUK_ASSERT_CTX_VALID(ctx);
13946 thr = (duk_hthread *) ctx;
13947 DUK_ASSERT(thr != NULL);
13948 DUK_ASSERT(thr->heap != NULL);
13949
13950 DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
13951
13952 top = duk_get_top(ctx);
13953 if (top < nvalues) {
13954 DUK_ERROR_API(thr, "not enough stack values for notify");
13955 return ret; /* unreachable */
13956 }
13957 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13958 duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
13959 for (idx = top - nvalues; idx < top; idx++) {
13960 duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx);
13961 duk_debug_write_tval(thr, tv);
13962 }
13963 duk_debug_write_eom(thr);
13964
13965 /* Return non-zero (true) if we have a good reason to believe
13966 * the notify was delivered; if we're still attached at least
13967 * a transport error was not indicated by the transport write
13968 * callback. This is not a 100% guarantee of course.
13969 */
13970 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13971 ret = 1;
13972 }
13973 }
13974 duk_pop_n(ctx, nvalues);
13975 return ret;
13976}
13977
13978DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
13979 duk_hthread *thr;
13980
13981 DUK_ASSERT_CTX_VALID(ctx);
13982 thr = (duk_hthread *) ctx;
13983 DUK_ASSERT(thr != NULL);
13984 DUK_ASSERT(thr->heap != NULL);
13985
13986 DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
13987
13988 /* Treat like a debugger statement: ignore when not attached. */
13989 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13990 DUK_HEAP_SET_PAUSED(thr->heap);
13991
13992 /* Pause on the next opcode executed. This is always safe to do even
13993 * inside the debugger message loop: the interrupt counter will be reset
13994 * to its proper value when the message loop exits.
13995 */
13996 thr->interrupt_init = 1;
13997 thr->interrupt_counter = 0;
13998 }
13999}
14000
14001#else /* DUK_USE_DEBUGGER_SUPPORT */
14002
14003DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
14004 duk_debug_read_function read_cb,
14005 duk_debug_write_function write_cb,
14006 duk_debug_peek_function peek_cb,
14007 duk_debug_read_flush_function read_flush_cb,
14008 duk_debug_write_flush_function write_flush_cb,
14009 duk_debug_request_function request_cb,
14010 duk_debug_detached_function detached_cb,
14011 void *udata) {
14012 DUK_ASSERT_CTX_VALID(ctx);
14013 DUK_UNREF(read_cb);
14014 DUK_UNREF(write_cb);
14015 DUK_UNREF(peek_cb);
14016 DUK_UNREF(read_flush_cb);
14017 DUK_UNREF(write_flush_cb);
14018 DUK_UNREF(request_cb);
14019 DUK_UNREF(detached_cb);
14020 DUK_UNREF(udata);
14021 DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
14022}
14023
14024DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
14025 DUK_ASSERT_CTX_VALID(ctx);
14026 DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
14027}
14028
14029DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
14030 /* nop */
14031 DUK_ASSERT_CTX_VALID(ctx);
14032 DUK_UNREF(ctx);
14033}
14034
14035DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
14036 duk_idx_t top;
14037
14038 DUK_ASSERT_CTX_VALID(ctx);
14039
14040 top = duk_get_top(ctx);
14041 if (top < nvalues) {
14042 DUK_ERROR_API((duk_hthread *) ctx, "not enough stack values for notify");
14043 return 0; /* unreachable */
14044 }
14045
14046 /* No debugger support, just pop values. */
14047 duk_pop_n(ctx, nvalues);
14048 return 0;
14049}
14050
14051DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
14052 /* Treat like debugger statement: nop */
14053 DUK_ASSERT_CTX_VALID(ctx);
14054 DUK_UNREF(ctx);
14055}
14056
14057#endif /* DUK_USE_DEBUGGER_SUPPORT */
14058#line 1 "duk_api_heap.c"
14059/*
14060 * Heap creation and destruction
14061 */
14062
14063/* include removed: duk_internal.h */
14064
14065typedef struct duk_internal_thread_state duk_internal_thread_state;
14066
14067struct duk_internal_thread_state {
14068 duk_ljstate lj;
14069 duk_bool_t handling_error;
14070 duk_hthread *curr_thread;
14071 duk_int_t call_recursion_depth;
14072};
14073
14074DUK_EXTERNAL
14075duk_context *duk_create_heap(duk_alloc_function alloc_func,
14076 duk_realloc_function realloc_func,
14077 duk_free_function free_func,
14078 void *heap_udata,
14079 duk_fatal_function fatal_handler) {
14080 duk_heap *heap = NULL;
14081 duk_context *ctx;
14082
14083 /* Assume that either all memory funcs are NULL or non-NULL, mixed
14084 * cases will now be unsafe.
14085 */
14086
14087 /* XXX: just assert non-NULL values here and make caller arguments
14088 * do the defaulting to the default implementations (smaller code)?
14089 */
14090
14091 if (!alloc_func) {
14092 DUK_ASSERT(realloc_func == NULL);
14093 DUK_ASSERT(free_func == NULL);
14094#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
14095 alloc_func = duk_default_alloc_function;
14096 realloc_func = duk_default_realloc_function;
14097 free_func = duk_default_free_function;
14098#else
14099 DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
14100 return NULL;
14101#endif
14102 } else {
14103 DUK_ASSERT(realloc_func != NULL);
14104 DUK_ASSERT(free_func != NULL);
14105 }
14106
14107 if (!fatal_handler) {
14108 fatal_handler = duk_default_fatal_handler;
14109 }
14110
14111 DUK_ASSERT(alloc_func != NULL);
14112 DUK_ASSERT(realloc_func != NULL);
14113 DUK_ASSERT(free_func != NULL);
14114 DUK_ASSERT(fatal_handler != NULL);
14115
14116 heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
14117 if (!heap) {
14118 return NULL;
14119 }
14120 ctx = (duk_context *) heap->heap_thread;
14121 DUK_ASSERT(ctx != NULL);
14122 DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
14123 return ctx;
14124}
14125
14126DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
14127 duk_hthread *thr = (duk_hthread *) ctx;
14128 duk_heap *heap;
14129
14130 if (!ctx) {
14131 return;
14132 }
14133 heap = thr->heap;
14134 DUK_ASSERT(heap != NULL);
14135
14136 duk_heap_free(heap);
14137}
14138
14139DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
14140 duk_hthread *thr = (duk_hthread *) ctx;
14141 duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
14142 duk_heap *heap;
14143 duk_ljstate *lj;
14144
14145 DUK_ASSERT_CTX_VALID(ctx);
14146 DUK_ASSERT(thr != NULL);
14147 DUK_ASSERT(thr->heap != NULL);
14148 DUK_ASSERT(state != NULL); /* unvalidated */
14149
14150 heap = thr->heap;
14151 lj = &heap->lj;
14152
14153 duk_push_tval(ctx, &lj->value1);
14154 duk_push_tval(ctx, &lj->value2);
14155
14156 DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
14157 snapshot->handling_error = heap->handling_error;
14158 snapshot->curr_thread = heap->curr_thread;
14159 snapshot->call_recursion_depth = heap->call_recursion_depth;
14160
14161 lj->jmpbuf_ptr = NULL;
14162 lj->type = DUK_LJ_TYPE_UNKNOWN;
14163 DUK_TVAL_SET_UNDEFINED(&lj->value1);
14164 DUK_TVAL_SET_UNDEFINED(&lj->value2);
14165 heap->handling_error = 0;
14166 heap->curr_thread = NULL;
14167 heap->call_recursion_depth = 0;
14168}
14169
14170DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
14171 duk_hthread *thr = (duk_hthread *) ctx;
14172 const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
14173 duk_heap *heap;
14174
14175 DUK_ASSERT_CTX_VALID(ctx);
14176 DUK_ASSERT(thr != NULL);
14177 DUK_ASSERT(thr->heap != NULL);
14178 DUK_ASSERT(state != NULL); /* unvalidated */
14179
14180 heap = thr->heap;
14181
14182 DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
14183 heap->handling_error = snapshot->handling_error;
14184 heap->curr_thread = snapshot->curr_thread;
14185 heap->call_recursion_depth = snapshot->call_recursion_depth;
14186
14187 duk_pop_2(ctx);
14188}
14189
14190/* XXX: better place for this */
14191DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
14192 duk_hthread *thr = (duk_hthread *) ctx;
14193 duk_hobject *h_glob;
14194 duk_hobject *h_prev_glob;
14195 duk_hobject *h_env;
14196 duk_hobject *h_prev_env;
14197
14198 DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
14199
14200 h_glob = duk_require_hobject(ctx, -1);
14201 DUK_ASSERT(h_glob != NULL);
14202
14203 /*
14204 * Replace global object.
14205 */
14206
14207 h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
14208 DUK_UNREF(h_prev_glob);
14209 thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
14210 DUK_HOBJECT_INCREF(thr, h_glob);
14211 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
14212
14213 /*
14214 * Replace lexical environment for global scope
14215 *
14216 * Create a new object environment for the global lexical scope.
14217 * We can't just reset the _Target property of the current one,
14218 * because the lexical scope is shared by other threads with the
14219 * same (initial) built-ins.
14220 */
14221
14222 (void) duk_push_object_helper(ctx,
14223 DUK_HOBJECT_FLAG_EXTENSIBLE |
14224 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
14225 -1); /* no prototype, updated below */
14226
14227 duk_dup(ctx, -2);
14228 duk_dup(ctx, -3);
14229
14230 /* [ ... new_glob new_env new_glob new_glob ] */
14231
14232 duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
14233 duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
14234
14235 /* [ ... new_glob new_env ] */
14236
14237 h_env = duk_get_hobject(ctx, -1);
14238 DUK_ASSERT(h_env != NULL);
14239
14240 h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
14241 thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env;
14242 DUK_HOBJECT_INCREF(thr, h_env);
14243 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
14244 DUK_UNREF(h_env); /* without refcounts */
14245 DUK_UNREF(h_prev_env);
14246
14247 /* [ ... new_glob new_env ] */
14248
14249 duk_pop_2(ctx);
14250
14251 /* [ ... ] */
14252}
14253#line 1 "duk_api_logging.c"
14254/*
14255 * Logging
14256 *
14257 * Current logging primitive is a sprintf-style log which is convenient
14258 * for most C code. Another useful primitive would be to log N arguments
14259 * from value stack (like the Ecmascript binding does).
14260 */
14261
14262/* include removed: duk_internal.h */
14263
14264DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) {
14265 /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */
14266 static const duk_uint16_t stridx_logfunc[6] = {
14267 DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO,
14268 DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL
14269 };
14270
14271 DUK_ASSERT_CTX_VALID(ctx);
14272
14273 if (level < 0) {
14274 level = 0;
14275 } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) {
14276 level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1;
14277 }
14278
14279 duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR);
14280 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG);
14281 duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]);
14282 duk_dup(ctx, -2);
14283
14284 /* [ ... Logger clog logfunc clog ] */
14285
14286 duk_push_vsprintf(ctx, fmt, ap);
14287
14288 /* [ ... Logger clog logfunc clog(=this) msg ] */
14289
14290 duk_call_method(ctx, 1 /*nargs*/);
14291
14292 /* [ ... Logger clog res ] */
14293
14294 duk_pop_3(ctx);
14295}
14296
14297DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) {
14298 va_list ap;
14299
14300 DUK_ASSERT_CTX_VALID(ctx);
14301
14302 va_start(ap, fmt);
14303 duk_log_va(ctx, level, fmt, ap);
14304 va_end(ap);
14305}
14306#line 1 "duk_api_memory.c"
14307/*
14308 * Memory calls.
14309 */
14310
14311/* include removed: duk_internal.h */
14312
14313DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) {
14314 duk_hthread *thr = (duk_hthread *) ctx;
14315
14316 DUK_ASSERT_CTX_VALID(ctx);
14317
14318 return DUK_ALLOC_RAW(thr->heap, size);
14319}
14320
14321DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) {
14322 duk_hthread *thr = (duk_hthread *) ctx;
14323
14324 DUK_ASSERT_CTX_VALID(ctx);
14325
14326 DUK_FREE_RAW(thr->heap, ptr);
14327}
14328
14329DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) {
14330 duk_hthread *thr = (duk_hthread *) ctx;
14331
14332 DUK_ASSERT_CTX_VALID(ctx);
14333
14334 return DUK_REALLOC_RAW(thr->heap, ptr, size);
14335}
14336
14337DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
14338 duk_hthread *thr = (duk_hthread *) ctx;
14339
14340 DUK_ASSERT_CTX_VALID(ctx);
14341
14342 return DUK_ALLOC(thr->heap, size);
14343}
14344
14345DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) {
14346 duk_hthread *thr = (duk_hthread *) ctx;
14347
14348 DUK_ASSERT_CTX_VALID(ctx);
14349
14350 DUK_FREE(thr->heap, ptr);
14351}
14352
14353DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
14354 duk_hthread *thr = (duk_hthread *) ctx;
14355
14356 DUK_ASSERT_CTX_VALID(ctx);
14357
14358 /*
14359 * Note: since this is an exposed API call, there should be
14360 * no way a mark-and-sweep could have a side effect on the
14361 * memory allocation behind 'ptr'; the pointer should never
14362 * be something that Duktape wants to change.
14363 *
14364 * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
14365 * have the storage location here anyway).
14366 */
14367
14368 return DUK_REALLOC(thr->heap, ptr, size);
14369}
14370
14371DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
14372 duk_hthread *thr = (duk_hthread *) ctx;
14373 duk_heap *heap;
14374
14375 DUK_ASSERT_CTX_VALID(ctx);
14376 DUK_ASSERT(out_funcs != NULL);
14377 DUK_ASSERT(thr != NULL);
14378 DUK_ASSERT(thr->heap != NULL);
14379
14380 heap = thr->heap;
14381 out_funcs->alloc_func = heap->alloc_func;
14382 out_funcs->realloc_func = heap->realloc_func;
14383 out_funcs->free_func = heap->free_func;
14384 out_funcs->udata = heap->heap_udata;
14385}
14386
14387DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
14388#ifdef DUK_USE_MARK_AND_SWEEP
14389 duk_hthread *thr = (duk_hthread *) ctx;
14390 duk_heap *heap;
14391
14392 DUK_UNREF(flags);
14393
14394 /* NULL accepted */
14395 if (!ctx) {
14396 return;
14397 }
14398 DUK_ASSERT_CTX_VALID(ctx);
14399 heap = thr->heap;
14400 DUK_ASSERT(heap != NULL);
14401
14402 DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
14403 duk_heap_mark_and_sweep(heap, 0);
14404#else
14405 DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring"));
14406 DUK_UNREF(ctx);
14407 DUK_UNREF(flags);
14408#endif
14409}
14410#line 1 "duk_api_object.c"
14411/*
14412 * Object handling: property access and other support functions.
14413 */
14414
14415/* include removed: duk_internal.h */
14416
14417/*
14418 * Property handling
14419 *
14420 * The API exposes only the most common property handling functions.
14421 * The caller can invoke Ecmascript built-ins for full control (e.g.
14422 * defineProperty, getOwnPropertyDescriptor).
14423 */
14424
14425DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) {
14426 duk_hthread *thr = (duk_hthread *) ctx;
14427 duk_tval *tv_obj;
14428 duk_tval *tv_key;
14429 duk_bool_t rc;
14430
14431 DUK_ASSERT_CTX_VALID(ctx);
14432
14433 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14434 * resize is not necessary for a property get right now.
14435 */
14436
14437 tv_obj = duk_require_tval(ctx, obj_index);
14438 tv_key = duk_require_tval(ctx, -1);
14439
14440 rc = duk_hobject_getprop(thr, tv_obj, tv_key);
14441 DUK_ASSERT(rc == 0 || rc == 1);
14442 /* a value is left on stack regardless of rc */
14443
14444 duk_remove(ctx, -2); /* remove key */
14445 return rc; /* 1 if property found, 0 otherwise */
14446}
14447
14448DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
14449 DUK_ASSERT_CTX_VALID(ctx);
14450 DUK_ASSERT(key != NULL);
14451
14452 obj_index = duk_require_normalize_index(ctx, obj_index);
14453 duk_push_string(ctx, key);
14454 return duk_get_prop(ctx, obj_index);
14455}
14456
14457DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
14458 DUK_ASSERT_CTX_VALID(ctx);
14459
14460 obj_index = duk_require_normalize_index(ctx, obj_index);
14461 duk_push_uarridx(ctx, arr_index);
14462 return duk_get_prop(ctx, obj_index);
14463}
14464
14465DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
14466 duk_hthread *thr = (duk_hthread *) ctx;
14467
14468 DUK_ASSERT_CTX_VALID(ctx);
14469 DUK_ASSERT_DISABLE(stridx >= 0);
14470 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14471 DUK_UNREF(thr);
14472
14473 obj_index = duk_require_normalize_index(ctx, obj_index);
14474 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
14475 return duk_get_prop(ctx, obj_index);
14476}
14477
14478DUK_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) {
14479 duk_bool_t rc;
14480
14481 DUK_ASSERT_CTX_VALID(ctx);
14482 DUK_ASSERT_DISABLE(stridx >= 0);
14483 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14484
14485 rc = duk_get_prop_stridx(ctx, obj_index, stridx);
14486 if (out_has_prop) {
14487 *out_has_prop = rc;
14488 }
14489 rc = duk_to_boolean(ctx, -1);
14490 DUK_ASSERT(rc == 0 || rc == 1);
14491 duk_pop(ctx);
14492 return rc;
14493}
14494
14495DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) {
14496 duk_hthread *thr = (duk_hthread *) ctx;
14497 duk_tval *tv_obj;
14498 duk_tval *tv_key;
14499 duk_tval *tv_val;
14500 duk_small_int_t throw_flag;
14501 duk_bool_t rc;
14502
14503 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14504 * resize is not necessary for a property put right now (putprop protects
14505 * against it internally).
14506 */
14507
14508 /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key,
14509 * idx_val is always (idx_key ^ 0x01).
14510 */
14511 DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
14512 (idx_key == -1 && (idx_key ^ 1) == -2));
14513 tv_obj = duk_require_tval(ctx, obj_idx);
14514 tv_key = duk_require_tval(ctx, idx_key);
14515 tv_val = duk_require_tval(ctx, idx_key ^ 1);
14516 throw_flag = duk_is_strict_call(ctx);
14517
14518 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
14519 DUK_ASSERT(rc == 0 || rc == 1);
14520
14521 duk_pop_2(ctx); /* remove key and value */
14522 return rc; /* 1 if property found, 0 otherwise */
14523}
14524
14525DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) {
14526 DUK_ASSERT_CTX_VALID(ctx);
14527 return duk__put_prop_shared(ctx, obj_idx, -2);
14528}
14529
14530DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
14531 DUK_ASSERT_CTX_VALID(ctx);
14532 DUK_ASSERT(key != NULL);
14533
14534 /* Careful here and with other duk_put_prop_xxx() helpers: the
14535 * target object and the property value may be in the same value
14536 * stack slot (unusual, but still conceptually clear).
14537 */
14538 obj_idx = duk_normalize_index(ctx, obj_idx);
14539 (void) duk_push_string(ctx, key);
14540 return duk__put_prop_shared(ctx, obj_idx, -1);
14541}
14542
14543DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
14544 DUK_ASSERT_CTX_VALID(ctx);
14545
14546 obj_idx = duk_require_normalize_index(ctx, obj_idx);
14547 duk_push_uarridx(ctx, arr_idx);
14548 return duk__put_prop_shared(ctx, obj_idx, -1);
14549}
14550
14551DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, 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);
14557 DUK_UNREF(thr);
14558
14559 obj_idx = duk_require_normalize_index(ctx, obj_idx);
14560 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
14561 return duk__put_prop_shared(ctx, obj_idx, -1);
14562}
14563
14564DUK_EXTERNAL duk_bool_t duk_del_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_small_int_t throw_flag;
14569 duk_bool_t rc;
14570
14571 DUK_ASSERT_CTX_VALID(ctx);
14572
14573 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14574 * resize is not necessary for a property delete right now.
14575 */
14576
14577 tv_obj = duk_require_tval(ctx, obj_index);
14578 tv_key = duk_require_tval(ctx, -1);
14579 throw_flag = duk_is_strict_call(ctx);
14580
14581 rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
14582 DUK_ASSERT(rc == 0 || rc == 1);
14583
14584 duk_pop(ctx); /* remove key */
14585 return rc;
14586}
14587
14588DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
14589 DUK_ASSERT_CTX_VALID(ctx);
14590 DUK_ASSERT(key != NULL);
14591
14592 obj_index = duk_require_normalize_index(ctx, obj_index);
14593 duk_push_string(ctx, key);
14594 return duk_del_prop(ctx, obj_index);
14595}
14596
14597DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
14598 DUK_ASSERT_CTX_VALID(ctx);
14599
14600 obj_index = duk_require_normalize_index(ctx, obj_index);
14601 duk_push_uarridx(ctx, arr_index);
14602 return duk_del_prop(ctx, obj_index);
14603}
14604
14605DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
14606 duk_hthread *thr = (duk_hthread *) ctx;
14607
14608 DUK_ASSERT_CTX_VALID(ctx);
14609 DUK_ASSERT_DISABLE(stridx >= 0);
14610 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14611 DUK_UNREF(thr);
14612
14613 obj_index = duk_require_normalize_index(ctx, obj_index);
14614 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
14615 return duk_del_prop(ctx, obj_index);
14616}
14617
14618DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) {
14619 duk_hthread *thr = (duk_hthread *) ctx;
14620 duk_tval *tv_obj;
14621 duk_tval *tv_key;
14622 duk_bool_t rc;
14623
14624 DUK_ASSERT_CTX_VALID(ctx);
14625
14626 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14627 * resize is not necessary for a property existence check right now.
14628 */
14629
14630 tv_obj = duk_require_tval(ctx, obj_index);
14631 tv_key = duk_require_tval(ctx, -1);
14632
14633 rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
14634 DUK_ASSERT(rc == 0 || rc == 1);
14635
14636 duk_pop(ctx); /* remove key */
14637 return rc; /* 1 if property found, 0 otherwise */
14638}
14639
14640DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
14641 DUK_ASSERT_CTX_VALID(ctx);
14642 DUK_ASSERT(key != NULL);
14643
14644 obj_index = duk_require_normalize_index(ctx, obj_index);
14645 duk_push_string(ctx, key);
14646 return duk_has_prop(ctx, obj_index);
14647}
14648
14649DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
14650 DUK_ASSERT_CTX_VALID(ctx);
14651
14652 obj_index = duk_require_normalize_index(ctx, obj_index);
14653 duk_push_uarridx(ctx, arr_index);
14654 return duk_has_prop(ctx, obj_index);
14655}
14656
14657DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
14658 duk_hthread *thr = (duk_hthread *) ctx;
14659
14660 DUK_ASSERT_CTX_VALID(ctx);
14661 DUK_ASSERT_DISABLE(stridx >= 0);
14662 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14663 DUK_UNREF(thr);
14664
14665 obj_index = duk_require_normalize_index(ctx, obj_index);
14666 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
14667 return duk_has_prop(ctx, obj_index);
14668}
14669
14670/* Define own property without inheritance looks and such. This differs from
14671 * [[DefineOwnProperty]] because special behaviors (like Array 'length') are
14672 * not invoked by this method. The caller must be careful to invoke any such
14673 * behaviors if necessary.
14674 */
14675DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) {
14676 duk_hthread *thr = (duk_hthread *) ctx;
14677 duk_hobject *obj;
14678 duk_hstring *key;
14679
14680 DUK_ASSERT_CTX_VALID(ctx);
14681
14682 obj = duk_require_hobject(ctx, obj_index);
14683 DUK_ASSERT(obj != NULL);
14684 key = duk_to_hstring(ctx, -2);
14685 DUK_ASSERT(key != NULL);
14686 DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
14687
14688 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
14689
14690 duk_pop(ctx); /* pop key */
14691}
14692
14693DUK_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) {
14694 duk_hthread *thr = (duk_hthread *) ctx;
14695 duk_hobject *obj;
14696
14697 DUK_ASSERT_CTX_VALID(ctx);
14698
14699 obj = duk_require_hobject(ctx, obj_index);
14700 DUK_ASSERT(obj != NULL);
14701
14702 duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags);
14703 /* value popped by call */
14704}
14705
14706DUK_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) {
14707 duk_hthread *thr = (duk_hthread *) ctx;
14708 duk_hobject *obj;
14709 duk_hstring *key;
14710
14711 DUK_ASSERT_CTX_VALID(ctx);
14712 DUK_ASSERT_DISABLE(stridx >= 0);
14713 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14714
14715 obj = duk_require_hobject(ctx, obj_index);
14716 DUK_ASSERT(obj != NULL);
14717 key = DUK_HTHREAD_GET_STRING(thr, stridx);
14718 DUK_ASSERT(key != NULL);
14719 DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
14720
14721 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
14722 /* value popped by call */
14723}
14724
14725DUK_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) {
14726 duk_hthread *thr = (duk_hthread *) ctx;
14727 duk_hobject *obj;
14728 duk_hstring *key;
14729
14730 DUK_ASSERT_CTX_VALID(ctx);
14731 DUK_ASSERT_DISABLE(stridx >= 0);
14732 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14733 DUK_ASSERT_DISABLE(builtin_idx >= 0);
14734 DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS);
14735
14736 obj = duk_require_hobject(ctx, obj_index);
14737 DUK_ASSERT(obj != NULL);
14738 key = DUK_HTHREAD_GET_STRING(thr, stridx);
14739 DUK_ASSERT(key != NULL);
14740
14741 duk_push_hobject(ctx, thr->builtins[builtin_idx]);
14742 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
14743 /* value popped by call */
14744}
14745
14746/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
14747 * setter/getter into an object property. This is needed by the 'arguments'
14748 * object creation code, function instance creation code, and Function.prototype.bind().
14749 */
14750
14751DUK_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) {
14752 duk_hthread *thr = (duk_hthread *) ctx;
14753 duk_hobject *obj = duk_require_hobject(ctx, obj_index);
14754 duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER];
14755 duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags);
14756}
14757
14758/* Object.defineProperty() equivalent C binding. */
14759DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) {
14760 duk_hthread *thr = (duk_hthread *) ctx;
14761 duk_idx_t idx_base;
14762 duk_hobject *obj;
14763 duk_hstring *key;
14764 duk_idx_t idx_value;
14765 duk_hobject *get;
14766 duk_hobject *set;
14767 duk_uint_t is_data_desc;
14768 duk_uint_t is_acc_desc;
14769
14770 DUK_ASSERT_CTX_VALID(ctx);
14771
14772 obj = duk_require_hobject(ctx, obj_index);
14773
14774 is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
14775 is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
14776 if (is_data_desc && is_acc_desc) {
14777 /* "Have" flags must not be conflicting so that they would
14778 * apply to both a plain property and an accessor at the same
14779 * time.
14780 */
14781 goto fail_invalid_desc;
14782 }
14783
14784 idx_base = duk_get_top_index(ctx);
14785 if (flags & DUK_DEFPROP_HAVE_SETTER) {
14786 duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
14787 DUK_TYPE_MASK_OBJECT |
14788 DUK_TYPE_MASK_LIGHTFUNC);
14789 set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
14790 if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
14791 goto fail_not_callable;
14792 }
14793 idx_base--;
14794 } else {
14795 set = NULL;
14796 }
14797 if (flags & DUK_DEFPROP_HAVE_GETTER) {
14798 duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
14799 DUK_TYPE_MASK_OBJECT |
14800 DUK_TYPE_MASK_LIGHTFUNC);
14801 get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
14802 if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
14803 goto fail_not_callable;
14804 }
14805 idx_base--;
14806 } else {
14807 get = NULL;
14808 }
14809 if (flags & DUK_DEFPROP_HAVE_VALUE) {
14810 idx_value = idx_base;
14811 idx_base--;
14812 } else {
14813 idx_value = (duk_idx_t) -1;
14814 }
14815 key = duk_require_hstring(ctx, idx_base);
14816
14817 duk_require_valid_index(ctx, idx_base);
14818
14819 duk_hobject_define_property_helper(ctx,
14820 flags /*defprop_flags*/,
14821 obj,
14822 key,
14823 idx_value,
14824 get,
14825 set);
14826
14827 /* Clean up stack */
14828
14829 duk_set_top(ctx, idx_base);
14830
14831 /* [ ... obj ... ] */
14832
14833 return;
14834
14835 fail_invalid_desc:
14836 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
14837 return;
14838
14839 fail_not_callable:
14840 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
14841 return;
14842}
14843
14844/*
14845 * Object related
14846 *
14847 * Note: seal() and freeze() are accessible through Ecmascript bindings,
14848 * and are not exposed through the API.
14849 */
14850
14851DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) {
14852 duk_hthread *thr = (duk_hthread *) ctx;
14853 duk_hobject *obj;
14854
14855 DUK_ASSERT_CTX_VALID(ctx);
14856
14857 obj = duk_get_hobject(ctx, obj_index);
14858 if (obj) {
14859 /* Note: this may fail, caller should protect the call if necessary */
14860 duk_hobject_compact_props(thr, obj);
14861 }
14862}
14863
14864/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
14865
14866DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) {
14867 DUK_ASSERT_CTX_VALID(ctx);
14868
14869 duk_dup(ctx, obj_index);
14870 duk_require_hobject_or_lfunc_coerce(ctx, -1);
14871 duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */
14872}
14873
14874DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) {
14875 DUK_ASSERT_CTX_VALID(ctx);
14876
14877 duk_require_hobject(ctx, enum_index);
14878 duk_dup(ctx, enum_index);
14879 return duk_hobject_enumerator_next(ctx, get_value);
14880}
14881
14882/*
14883 * Helpers for writing multiple properties
14884 */
14885
14886DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) {
14887 const duk_function_list_entry *ent = funcs;
14888
14889 DUK_ASSERT_CTX_VALID(ctx);
14890
14891 obj_index = duk_require_normalize_index(ctx, obj_index);
14892 if (ent != NULL) {
14893 while (ent->key != NULL) {
14894 duk_push_c_function(ctx, ent->value, ent->nargs);
14895 duk_put_prop_string(ctx, obj_index, ent->key);
14896 ent++;
14897 }
14898 }
14899}
14900
14901DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) {
14902 const duk_number_list_entry *ent = numbers;
14903
14904 DUK_ASSERT_CTX_VALID(ctx);
14905
14906 obj_index = duk_require_normalize_index(ctx, obj_index);
14907 if (ent != NULL) {
14908 while (ent->key != NULL) {
14909 duk_push_number(ctx, ent->value);
14910 duk_put_prop_string(ctx, obj_index, ent->key);
14911 ent++;
14912 }
14913 }
14914}
14915
14916/*
14917 * Shortcut for accessing global object properties
14918 */
14919
14920DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) {
14921 duk_hthread *thr = (duk_hthread *) ctx;
14922 duk_bool_t ret;
14923
14924 DUK_ASSERT_CTX_VALID(ctx);
14925 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
14926
14927 /* XXX: direct implementation */
14928
14929 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
14930 ret = duk_get_prop_string(ctx, -1, key);
14931 duk_remove(ctx, -2);
14932 return ret;
14933}
14934
14935DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) {
14936 duk_hthread *thr = (duk_hthread *) ctx;
14937 duk_bool_t ret;
14938
14939 DUK_ASSERT_CTX_VALID(ctx);
14940 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
14941
14942 /* XXX: direct implementation */
14943
14944 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
14945 duk_insert(ctx, -2);
14946 ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */
14947 duk_pop(ctx);
14948 return ret;
14949}
14950
14951/*
14952 * Object prototype
14953 */
14954
14955DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) {
14956 duk_hthread *thr = (duk_hthread *) ctx;
14957 duk_hobject *obj;
14958 duk_hobject *proto;
14959
14960 DUK_ASSERT_CTX_VALID(ctx);
14961 DUK_UNREF(thr);
14962
14963 obj = duk_require_hobject(ctx, index);
14964 DUK_ASSERT(obj != NULL);
14965
14966 /* XXX: shared helper for duk_push_hobject_or_undefined()? */
14967 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
14968 if (proto) {
14969 duk_push_hobject(ctx, proto);
14970 } else {
14971 duk_push_undefined(ctx);
14972 }
14973}
14974
14975DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) {
14976 duk_hthread *thr = (duk_hthread *) ctx;
14977 duk_hobject *obj;
14978 duk_hobject *proto;
14979
14980 DUK_ASSERT_CTX_VALID(ctx);
14981
14982 obj = duk_require_hobject(ctx, index);
14983 DUK_ASSERT(obj != NULL);
14984 duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED |
14985 DUK_TYPE_MASK_OBJECT);
14986 proto = duk_get_hobject(ctx, -1);
14987 /* proto can also be NULL here (allowed explicitly) */
14988
14989#if defined(DUK_USE_ROM_OBJECTS)
14990 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
14991 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */
14992 return;
14993 }
14994#endif
14995
14996 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
14997
14998 duk_pop(ctx);
14999}
15000
15001/*
15002 * Object finalizer
15003 */
15004
15005/* XXX: these could be implemented as macros calling an internal function
15006 * directly.
15007 * XXX: same issue as with Duktape.fin: there's no way to delete the property
15008 * now (just set it to undefined).
15009 */
15010DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t index) {
15011 DUK_ASSERT_CTX_VALID(ctx);
15012
15013 duk_get_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
15014}
15015
15016DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) {
15017 DUK_ASSERT_CTX_VALID(ctx);
15018
15019 duk_put_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
15020}
15021#line 1 "duk_api_stack.c"
15022/*
15023 * API calls related to general value stack manipulation: resizing the value
15024 * stack, pushing and popping values, type checking and reading values,
15025 * coercing values, etc.
15026 *
15027 * Also contains internal functions (such as duk_get_tval()), defined
15028 * in duk_api_internal.h, with semantics similar to the public API.
15029 */
15030
15031/* XXX: repetition of stack pre-checks -> helper or macro or inline */
15032/* XXX: shared api error strings, and perhaps even throw code for rare cases? */
15033
15034/* include removed: duk_internal.h */
15035
15036/*
15037 * Forward declarations
15038 */
15039
15040DUK_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);
15041
15042/*
15043 * Global state for working around missing variadic macros
15044 */
15045
15046#ifndef DUK_USE_VARIADIC_MACROS
15047DUK_EXTERNAL const char *duk_api_global_filename = NULL;
15048DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
15049#endif
15050
15051/*
15052 * Misc helpers
15053 */
15054
15055/* Check that there's room to push one value. */
15056#if defined(DUK_USE_VALSTACK_UNSAFE)
15057/* Faster but value stack overruns are memory unsafe. */
15058#define DUK__CHECK_SPACE() do { \
15059 DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
15060 } while (0)
15061#else
15062#define DUK__CHECK_SPACE() do { \
15063 if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
15064 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \
15065 } \
15066 } while (0)
15067#endif
15068
15069DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag);
15070
15071DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
15072 duk_hthread *thr;
15073 duk_tval *tv;
15074 duk_small_int_t c;
15075 duk_double_t d;
15076
15077 thr = (duk_hthread *) ctx;
15078
15079 tv = duk_get_tval(ctx, index);
15080 if (tv == NULL) {
15081 goto error_notnumber;
15082 }
15083
15084 /*
15085 * Special cases like NaN and +/- Infinity are handled explicitly
15086 * because a plain C coercion from double to int handles these cases
15087 * in undesirable ways. For instance, NaN may coerce to INT_MIN
15088 * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX).
15089 *
15090 * This double-to-int coercion differs from ToInteger() because it
15091 * has a finite range (ToInteger() allows e.g. +/- Infinity). It
15092 * also differs from ToInt32() because the INT_MIN/INT_MAX clamping
15093 * depends on the size of the int type on the platform. In particular,
15094 * on platforms with a 64-bit int type, the full range is allowed.
15095 */
15096
15097#if defined(DUK_USE_FASTINT)
15098 if (DUK_TVAL_IS_FASTINT(tv)) {
15099 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
15100#if (DUK_INT_MAX <= 0x7fffffffL)
15101 /* Clamping only necessary for 32-bit ints. */
15102 if (t < DUK_INT_MIN) {
15103 t = DUK_INT_MIN;
15104 } else if (t > DUK_INT_MAX) {
15105 t = DUK_INT_MAX;
15106 }
15107#endif
15108 return (duk_int_t) t;
15109 }
15110#endif
15111
15112 if (DUK_TVAL_IS_NUMBER(tv)) {
15113 d = DUK_TVAL_GET_NUMBER(tv);
15114 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
15115 if (c == DUK_FP_NAN) {
15116 return 0;
15117 } else if (d < (duk_double_t) DUK_INT_MIN) {
15118 /* covers -Infinity */
15119 return DUK_INT_MIN;
15120 } else if (d > (duk_double_t) DUK_INT_MAX) {
15121 /* covers +Infinity */
15122 return DUK_INT_MAX;
15123 } else {
15124 /* coerce towards zero */
15125 return (duk_int_t) d;
15126 }
15127 }
15128
15129 error_notnumber:
15130
15131 if (require) {
15132 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
15133 /* not reachable */
15134 }
15135 return 0;
15136}
15137
15138DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
15139 duk_hthread *thr;
15140 duk_tval *tv;
15141 duk_small_int_t c;
15142 duk_double_t d;
15143
15144 /* Same as above but for unsigned int range. */
15145
15146 thr = (duk_hthread *) ctx;
15147
15148 tv = duk_get_tval(ctx, index);
15149 if (tv == NULL) {
15150 goto error_notnumber;
15151 }
15152
15153#if defined(DUK_USE_FASTINT)
15154 if (DUK_TVAL_IS_FASTINT(tv)) {
15155 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
15156 if (t < 0) {
15157 t = 0;
15158 }
15159#if (DUK_UINT_MAX <= 0xffffffffUL)
15160 /* Clamping only necessary for 32-bit ints. */
15161 else if (t > DUK_UINT_MAX) {
15162 t = DUK_UINT_MAX;
15163 }
15164#endif
15165 return (duk_uint_t) t;
15166 }
15167#endif
15168
15169 if (DUK_TVAL_IS_NUMBER(tv)) {
15170 d = DUK_TVAL_GET_NUMBER(tv);
15171 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
15172 if (c == DUK_FP_NAN) {
15173 return 0;
15174 } else if (d < 0.0) {
15175 /* covers -Infinity */
15176 return (duk_uint_t) 0;
15177 } else if (d > (duk_double_t) DUK_UINT_MAX) {
15178 /* covers +Infinity */
15179 return (duk_uint_t) DUK_UINT_MAX;
15180 } else {
15181 /* coerce towards zero */
15182 return (duk_uint_t) d;
15183 }
15184 }
15185
15186 error_notnumber:
15187
15188 if (require) {
15189 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
15190 /* not reachable */
15191 }
15192 return 0;
15193}
15194
15195/*
15196 * Stack index validation/normalization and getting a stack duk_tval ptr.
15197 *
15198 * These are called by many API entrypoints so the implementations must be
15199 * fast and "inlined".
15200 *
15201 * There's some repetition because of this; keep the functions in sync.
15202 */
15203
15204DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) {
15205 duk_hthread *thr = (duk_hthread *) ctx;
15206 duk_uidx_t vs_size;
15207 duk_uidx_t uindex;
15208
15209 DUK_ASSERT_CTX_VALID(ctx);
15210 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15211
15212 /* Care must be taken to avoid pointer wrapping in the index
15213 * validation. For instance, on a 32-bit platform with 8-byte
15214 * duk_tval the index 0x20000000UL would wrap the memory space
15215 * once.
15216 */
15217
15218 /* Assume value stack sizes (in elements) fits into duk_idx_t. */
15219 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15220 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15221 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
15222
15223 if (index < 0) {
15224 uindex = vs_size + (duk_uidx_t) index;
15225 } else {
15226 /* since index non-negative */
15227 DUK_ASSERT(index != DUK_INVALID_INDEX);
15228 uindex = (duk_uidx_t) index;
15229 }
15230
15231 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15232 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15233
15234 if (DUK_LIKELY(uindex < vs_size)) {
15235 return (duk_idx_t) uindex;
15236 }
15237 return DUK_INVALID_INDEX;
15238}
15239
15240DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index) {
15241 duk_hthread *thr = (duk_hthread *) ctx;
15242 duk_uidx_t vs_size;
15243 duk_uidx_t uindex;
15244
15245 DUK_ASSERT_CTX_VALID(ctx);
15246 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15247
15248 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15249 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15250 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
15251
15252 if (index < 0) {
15253 uindex = vs_size + (duk_uidx_t) index;
15254 } else {
15255 DUK_ASSERT(index != DUK_INVALID_INDEX);
15256 uindex = (duk_uidx_t) index;
15257 }
15258
15259 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15260 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15261
15262 if (DUK_LIKELY(uindex < vs_size)) {
15263 return (duk_idx_t) uindex;
15264 }
15265 DUK_ERROR_API_INDEX(thr, index);
15266 return 0; /* unreachable */
15267}
15268
15269DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) {
15270 duk_hthread *thr = (duk_hthread *) ctx;
15271 duk_uidx_t vs_size;
15272 duk_uidx_t uindex;
15273
15274 DUK_ASSERT_CTX_VALID(ctx);
15275 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15276
15277 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15278 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15279 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
15280
15281 if (index < 0) {
15282 uindex = vs_size + (duk_uidx_t) index;
15283 } else {
15284 DUK_ASSERT(index != DUK_INVALID_INDEX);
15285 uindex = (duk_uidx_t) index;
15286 }
15287
15288 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15289 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15290
15291 if (DUK_LIKELY(uindex < vs_size)) {
15292 return thr->valstack_bottom + uindex;
15293 }
15294 return NULL;
15295}
15296
15297DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
15298 duk_hthread *thr = (duk_hthread *) ctx;
15299 duk_uidx_t vs_size;
15300 duk_uidx_t uindex;
15301
15302 DUK_ASSERT_CTX_VALID(ctx);
15303 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15304
15305 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15306 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15307 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
15308
15309 /* Use unsigned arithmetic to optimize comparison. */
15310 if (index < 0) {
15311 uindex = vs_size + (duk_uidx_t) index;
15312 } else {
15313 DUK_ASSERT(index != DUK_INVALID_INDEX);
15314 uindex = (duk_uidx_t) index;
15315 }
15316
15317 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15318 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15319
15320 if (DUK_LIKELY(uindex < vs_size)) {
15321 return thr->valstack_bottom + uindex;
15322 }
15323 DUK_ERROR_API_INDEX(thr, index);
15324 return NULL;
15325}
15326
15327/* Non-critical. */
15328DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index) {
15329 DUK_ASSERT_CTX_VALID(ctx);
15330 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15331
15332 return (duk_normalize_index(ctx, index) >= 0);
15333}
15334
15335/* Non-critical. */
15336DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
15337 duk_hthread *thr = (duk_hthread *) ctx;
15338
15339 DUK_ASSERT_CTX_VALID(ctx);
15340 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15341
15342 if (duk_normalize_index(ctx, index) < 0) {
15343 DUK_ERROR_API_INDEX(thr, index);
15344 return; /* unreachable */
15345 }
15346}
15347
15348/*
15349 * Value stack top handling
15350 */
15351
15352DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
15353 duk_hthread *thr = (duk_hthread *) ctx;
15354
15355 DUK_ASSERT_CTX_VALID(ctx);
15356
15357 return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
15358}
15359
15360/* Set stack top within currently allocated range, but don't reallocate.
15361 * This is performance critical especially for call handling, so whenever
15362 * changing, profile and look at generated code.
15363 */
15364DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
15365 duk_hthread *thr = (duk_hthread *) ctx;
15366 duk_uidx_t vs_size;
15367 duk_uidx_t vs_limit;
15368 duk_uidx_t uindex;
15369 duk_tval *tv;
15370
15371 DUK_ASSERT_CTX_VALID(ctx);
15372 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15373
15374 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15375 DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
15376 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15377 vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
15378
15379 if (index < 0) {
15380 /* Negative indices are always within allocated stack but
15381 * must not go below zero index.
15382 */
15383 uindex = vs_size + (duk_uidx_t) index;
15384 } else {
15385 /* Positive index can be higher than valstack top but must
15386 * not go above allocated stack (equality is OK).
15387 */
15388 uindex = (duk_uidx_t) index;
15389 }
15390
15391 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15392 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15393 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
15394
15395#if defined(DUK_USE_VALSTACK_UNSAFE)
15396 DUK_ASSERT(uindex <= vs_limit);
15397 DUK_UNREF(vs_limit);
15398#else
15399 if (DUK_UNLIKELY(uindex > vs_limit)) {
15400 DUK_ERROR_API_INDEX(thr, index);
15401 return; /* unreachable */
15402 }
15403#endif
15404 DUK_ASSERT(uindex <= vs_limit);
15405
15406 /* Handle change in value stack top. Respect value stack
15407 * initialization policy: 'undefined' above top. Note that
15408 * DECREF may cause a side effect that reallocates valstack,
15409 * so must relookup after DECREF.
15410 */
15411
15412 if (uindex >= vs_size) {
15413 /* Stack size increases or stays the same. */
15414#if defined(DUK_USE_ASSERTIONS)
15415 duk_uidx_t count;
15416
15417 count = uindex - vs_size;
15418 while (count != 0) {
15419 count--;
15420 tv = thr->valstack_top + count;
15421 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
15422 }
15423#endif
15424 thr->valstack_top = thr->valstack_bottom + uindex;
15425 } else {
15426 /* Stack size decreases. */
15427#if defined(DUK_USE_REFERENCE_COUNTING)
15428 duk_uidx_t count;
15429
15430 count = vs_size - uindex;
15431 DUK_ASSERT(count > 0);
15432 while (count > 0) {
15433 count--;
15434 tv = --thr->valstack_top; /* tv -> value just before prev top value; must relookup */
15435 DUK_ASSERT(tv >= thr->valstack_bottom);
15436 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
15437 }
15438#else /* DUK_USE_REFERENCE_COUNTING */
15439 duk_uidx_t count;
15440 duk_tval *tv_end;
15441
15442 count = vs_size - uindex;
15443 tv = thr->valstack_top;
15444 tv_end = tv - count;
15445 DUK_ASSERT(tv > tv_end);
15446 do {
15447 tv--;
15448 DUK_TVAL_SET_UNDEFINED(tv);
15449 } while (tv != tv_end);
15450 thr->valstack_top = tv_end;
15451#endif /* DUK_USE_REFERENCE_COUNTING */
15452 }
15453}
15454
15455DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
15456 duk_hthread *thr = (duk_hthread *) ctx;
15457 duk_idx_t ret;
15458
15459 DUK_ASSERT_CTX_VALID(ctx);
15460
15461 ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
15462 if (DUK_UNLIKELY(ret < 0)) {
15463 /* Return invalid index; if caller uses this without checking
15464 * in another API call, the index won't map to a valid stack
15465 * entry.
15466 */
15467 return DUK_INVALID_INDEX;
15468 }
15469 return ret;
15470}
15471
15472DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
15473 duk_hthread *thr = (duk_hthread *) ctx;
15474 duk_idx_t ret;
15475
15476 DUK_ASSERT_CTX_VALID(ctx);
15477
15478 ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
15479 if (DUK_UNLIKELY(ret < 0)) {
15480 DUK_ERROR_API_INDEX(thr, -1);
15481 return 0; /* unreachable */
15482 }
15483 return ret;
15484}
15485
15486/*
15487 * Value stack resizing.
15488 *
15489 * This resizing happens above the current "top": the value stack can be
15490 * grown or shrunk, but the "top" is not affected. The value stack cannot
15491 * be resized to a size below the current "top".
15492 *
15493 * The low level reallocation primitive must carefully recompute all value
15494 * stack pointers, and must also work if ALL pointers are NULL. The resize
15495 * is quite tricky because the valstack realloc may cause a mark-and-sweep,
15496 * which may run finalizers. Running finalizers may resize the valstack
15497 * recursively (the same value stack we're working on). So, after realloc
15498 * returns, we know that the valstack "top" should still be the same (there
15499 * should not be live values above the "top"), but its underlying size and
15500 * pointer may have changed.
15501 */
15502
15503/* XXX: perhaps refactor this to allow caller to specify some parameters, or
15504 * at least a 'compact' flag which skips any spare or round-up .. useful for
15505 * emergency gc.
15506 */
15507
15508DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) {
15509 duk_hthread *thr = (duk_hthread *) ctx;
15510 duk_ptrdiff_t old_bottom_offset;
15511 duk_ptrdiff_t old_top_offset;
15512 duk_ptrdiff_t old_end_offset_post;
15513#ifdef DUK_USE_DEBUG
15514 duk_ptrdiff_t old_end_offset_pre;
15515 duk_tval *old_valstack_pre;
15516 duk_tval *old_valstack_post;
15517#endif
15518 duk_tval *new_valstack;
15519 duk_size_t new_alloc_size;
15520 duk_tval *p;
15521
15522 DUK_ASSERT_CTX_VALID(ctx);
15523 DUK_ASSERT(thr != NULL);
15524 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
15525 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15526 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
15527 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
15528 DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */
15529 DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
15530
15531 /* get pointer offsets for tweaking below */
15532 old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
15533 old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
15534#ifdef DUK_USE_DEBUG
15535 old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */
15536 old_valstack_pre = thr->valstack;
15537#endif
15538
15539 /* Allocate a new valstack.
15540 *
15541 * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
15542 * invalidate the original thr->valstack base pointer inside the realloc
15543 * process. See doc/memory-management.rst.
15544 */
15545
15546 new_alloc_size = sizeof(duk_tval) * new_size;
15547 new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
15548 if (!new_valstack) {
15549 /* Because new_size != 0, if condition doesn't need to be
15550 * (new_valstack != NULL || new_size == 0).
15551 */
15552 DUK_ASSERT(new_size != 0);
15553 DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)",
15554 (unsigned long) new_size, (unsigned long) new_alloc_size));
15555 return 0;
15556 }
15557
15558 /* Note: the realloc may have triggered a mark-and-sweep which may
15559 * have resized our valstack internally. However, the mark-and-sweep
15560 * MUST NOT leave the stack bottom/top in a different state. Particular
15561 * assumptions and facts:
15562 *
15563 * - The thr->valstack pointer may be different after realloc,
15564 * and the offset between thr->valstack_end <-> thr->valstack
15565 * may have changed.
15566 * - The offset between thr->valstack_bottom <-> thr->valstack
15567 * and thr->valstack_top <-> thr->valstack MUST NOT have changed,
15568 * because mark-and-sweep must adhere to a strict stack policy.
15569 * In other words, logical bottom and top MUST NOT have changed.
15570 * - All values above the top are unreachable but are initialized
15571 * to UNDEFINED, up to the post-realloc valstack_end.
15572 * - 'old_end_offset' must be computed after realloc to be correct.
15573 */
15574
15575 DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
15576 DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
15577
15578 /* success, fixup pointers */
15579 old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */
15580#ifdef DUK_USE_DEBUG
15581 old_valstack_post = thr->valstack;
15582#endif
15583 thr->valstack = new_valstack;
15584 thr->valstack_end = new_valstack + new_size;
15585#if !defined(DUK_USE_PREFER_SIZE)
15586 thr->valstack_size = new_size;
15587#endif
15588 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
15589 thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset);
15590
15591 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
15592 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15593 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
15594
15595 /* useful for debugging */
15596#ifdef DUK_USE_DEBUG
15597 if (old_end_offset_pre != old_end_offset_post) {
15598 DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
15599 "end offset changed: %lu -> %lu",
15600 (unsigned long) old_end_offset_pre,
15601 (unsigned long) old_end_offset_post));
15602 }
15603 if (old_valstack_pre != old_valstack_post) {
15604 DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
15605 (void *) old_valstack_pre,
15606 (void *) old_valstack_post));
15607 }
15608#endif
15609
15610 DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, "
15611 "new pointers: start=%p end=%p bottom=%p top=%p",
15612 (unsigned long) new_size, (unsigned long) new_alloc_size,
15613 (long) (thr->valstack_bottom - thr->valstack),
15614 (long) (thr->valstack_top - thr->valstack),
15615 (void *) thr->valstack, (void *) thr->valstack_end,
15616 (void *) thr->valstack_bottom, (void *) thr->valstack_top));
15617
15618 /* Init newly allocated slots (only). */
15619 p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
15620 while (p < thr->valstack_end) {
15621 /* Never executed if new size is smaller. */
15622 DUK_TVAL_SET_UNDEFINED(p);
15623 p++;
15624 }
15625
15626 /* Assert for value stack initialization policy. */
15627#if defined(DUK_USE_ASSERTIONS)
15628 p = thr->valstack_top;
15629 while (p < thr->valstack_end) {
15630 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
15631 p++;
15632 }
15633#endif
15634
15635 return 1;
15636}
15637
15638DUK_INTERNAL
15639duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
15640 duk_size_t min_new_size,
15641 duk_small_uint_t flags) {
15642 duk_hthread *thr = (duk_hthread *) ctx;
15643 duk_size_t old_size;
15644 duk_size_t new_size;
15645 duk_bool_t is_shrink = 0;
15646 duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK);
15647 duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT);
15648 duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW);
15649
15650 DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, "
15651 "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d",
15652 (unsigned long) min_new_size,
15653 (long) (thr->valstack_end - thr->valstack),
15654 (long) (thr->valstack_top - thr->valstack),
15655 (long) (thr->valstack_bottom - thr->valstack),
15656 (int) shrink_flag, (int) compact_flag, (int) throw_flag));
15657
15658 DUK_ASSERT_CTX_VALID(ctx);
15659 DUK_ASSERT(thr != NULL);
15660 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
15661 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15662 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
15663
15664#if defined(DUK_USE_PREFER_SIZE)
15665 old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
15666#else
15667 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
15668 old_size = thr->valstack_size;
15669#endif
15670
15671 if (min_new_size <= old_size) {
15672 is_shrink = 1;
15673 if (!shrink_flag ||
15674 old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) {
15675 DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack"));
15676 return 1;
15677 }
15678 }
15679
15680 new_size = min_new_size;
15681 if (!compact_flag) {
15682 if (is_shrink) {
15683 /* shrink case; leave some spare */
15684 new_size += DUK_VALSTACK_SHRINK_SPARE;
15685 }
15686
15687 /* round up roughly to next 'grow step' */
15688 new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
15689 }
15690
15691 DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)",
15692 (const char *) (new_size > old_size ? "grow" : "shrink"),
15693 (unsigned long) old_size, (unsigned long) new_size,
15694 (unsigned long) min_new_size));
15695
15696 if (new_size > thr->valstack_max) {
15697 /* Note: may be triggered even if minimal new_size would not reach the limit,
15698 * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account).
15699 */
15700 if (throw_flag) {
15701 DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
15702 } else {
15703 return 0;
15704 }
15705 }
15706
15707 /*
15708 * When resizing the valstack, a mark-and-sweep may be triggered for
15709 * the allocation of the new valstack. If the mark-and-sweep needs
15710 * to use our thread for something, it may cause *the same valstack*
15711 * to be resized recursively. This happens e.g. when mark-and-sweep
15712 * finalizers are called. This is taken into account carefully in
15713 * duk__resize_valstack().
15714 *
15715 * 'new_size' is known to be <= valstack_max, which ensures that
15716 * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
15717 */
15718
15719 if (!duk__resize_valstack(ctx, new_size)) {
15720 if (is_shrink) {
15721 DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore"));
15722 return 1;
15723 }
15724
15725 DUK_DD(DUK_DDPRINT("valstack resize failed"));
15726
15727 if (throw_flag) {
15728 DUK_ERROR_ALLOC_DEFMSG(thr);
15729 } else {
15730 return 0;
15731 }
15732 }
15733
15734 DUK_DDD(DUK_DDDPRINT("valstack resize successful"));
15735 return 1;
15736}
15737
15738DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) {
15739 duk_hthread *thr = (duk_hthread *) ctx;
15740 duk_size_t min_new_size;
15741
15742 DUK_ASSERT_CTX_VALID(ctx);
15743 DUK_ASSERT(thr != NULL);
15744
15745 if (DUK_UNLIKELY(extra < 0)) {
15746 /* Clamping to zero makes the API more robust to calling code
15747 * calculation errors.
15748 */
15749 extra = 0;
15750 }
15751
15752 min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
15753 return duk_valstack_resize_raw(ctx,
15754 min_new_size, /* min_new_size */
15755 0 /* no shrink */ | /* flags */
15756 0 /* no compact */ |
15757 0 /* no throw */);
15758}
15759
15760DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) {
15761 duk_hthread *thr = (duk_hthread *) ctx;
15762 duk_size_t min_new_size;
15763
15764 DUK_ASSERT_CTX_VALID(ctx);
15765 DUK_ASSERT(thr != NULL);
15766
15767 if (DUK_UNLIKELY(extra < 0)) {
15768 /* Clamping to zero makes the API more robust to calling code
15769 * calculation errors.
15770 */
15771 extra = 0;
15772 }
15773
15774 min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
15775 (void) duk_valstack_resize_raw(ctx,
15776 min_new_size, /* min_new_size */
15777 0 /* no shrink */ | /* flags */
15778 0 /* no compact */ |
15779 DUK_VSRESIZE_FLAG_THROW);
15780}
15781
15782DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) {
15783 duk_hthread *thr;
15784 duk_size_t min_new_size;
15785
15786 DUK_ASSERT_CTX_VALID(ctx);
15787 thr = (duk_hthread *) ctx;
15788
15789 if (DUK_UNLIKELY(top < 0)) {
15790 /* Clamping to zero makes the API more robust to calling code
15791 * calculation errors.
15792 */
15793 top = 0;
15794 }
15795
15796 min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA;
15797 return duk_valstack_resize_raw(ctx,
15798 min_new_size, /* min_new_size */
15799 0 /* no shrink */ | /* flags */
15800 0 /* no compact */ |
15801 0 /* no throw */);
15802}
15803
15804DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) {
15805 duk_hthread *thr;
15806 duk_size_t min_new_size;
15807
15808 DUK_ASSERT_CTX_VALID(ctx);
15809 thr = (duk_hthread *) ctx;
15810
15811 if (DUK_UNLIKELY(top < 0)) {
15812 /* Clamping to zero makes the API more robust to calling code
15813 * calculation errors.
15814 */
15815 top = 0;
15816 }
15817
15818 min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA;
15819 (void) duk_valstack_resize_raw(ctx,
15820 min_new_size, /* min_new_size */
15821 0 /* no shrink */ | /* flags */
15822 0 /* no compact */ |
15823 DUK_VSRESIZE_FLAG_THROW);
15824}
15825
15826/*
15827 * Basic stack manipulation: swap, dup, insert, replace, etc
15828 */
15829
15830DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
15831 duk_tval *tv1;
15832 duk_tval *tv2;
15833 duk_tval tv_tmp;
15834
15835 DUK_ASSERT_CTX_VALID(ctx);
15836
15837 tv1 = duk_require_tval(ctx, index1);
15838 DUK_ASSERT(tv1 != NULL);
15839 tv2 = duk_require_tval(ctx, index2);
15840 DUK_ASSERT(tv2 != NULL);
15841
15842 /* If tv1==tv2 this is a NOP, no check is needed */
15843 DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
15844 DUK_TVAL_SET_TVAL(tv1, tv2);
15845 DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
15846}
15847
15848DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t index) {
15849 DUK_ASSERT_CTX_VALID(ctx);
15850
15851 duk_swap(ctx, index, -1);
15852}
15853
15854DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) {
15855 duk_hthread *thr;
15856 duk_tval *tv_from;
15857 duk_tval *tv_to;
15858
15859 DUK_ASSERT_CTX_VALID(ctx);
15860 thr = (duk_hthread *) ctx;
15861 DUK__CHECK_SPACE();
15862
15863 tv_from = duk_require_tval(ctx, from_index);
15864 tv_to = thr->valstack_top++;
15865 DUK_ASSERT(tv_from != NULL);
15866 DUK_ASSERT(tv_to != NULL);
15867 DUK_TVAL_SET_TVAL(tv_to, tv_from);
15868 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
15869}
15870
15871DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
15872 duk_hthread *thr;
15873 duk_tval *tv_from;
15874 duk_tval *tv_to;
15875
15876 DUK_ASSERT_CTX_VALID(ctx);
15877 thr = (duk_hthread *) ctx;
15878 DUK__CHECK_SPACE();
15879
15880 if (thr->valstack_top - thr->valstack_bottom <= 0) {
15881 DUK_ERROR_API_INDEX(thr, -1);
15882 return; /* unreachable */
15883 }
15884 tv_from = thr->valstack_top - 1;
15885 tv_to = thr->valstack_top++;
15886 DUK_ASSERT(tv_from != NULL);
15887 DUK_ASSERT(tv_to != NULL);
15888 DUK_TVAL_SET_TVAL(tv_to, tv_from);
15889 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
15890}
15891
15892DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
15893 duk_tval *p;
15894 duk_tval *q;
15895 duk_tval tv_tmp;
15896 duk_size_t nbytes;
15897
15898 DUK_ASSERT_CTX_VALID(ctx);
15899
15900 p = duk_require_tval(ctx, to_index);
15901 DUK_ASSERT(p != NULL);
15902 q = duk_require_tval(ctx, -1);
15903 DUK_ASSERT(q != NULL);
15904
15905 DUK_ASSERT(q >= p);
15906
15907 /* nbytes
15908 * <--------->
15909 * [ ... | p | x | x | q ]
15910 * => [ ... | q | p | x | x ]
15911 */
15912
15913 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
15914
15915 DUK_DDD(DUK_DDDPRINT("duk_insert: to_index=%ld, p=%p, q=%p, nbytes=%lu",
15916 (long) to_index, (void *) p, (void *) q, (unsigned long) nbytes));
15917
15918 /* No net refcount changes. */
15919
15920 if (nbytes > 0) {
15921 DUK_TVAL_SET_TVAL(&tv_tmp, q);
15922 DUK_ASSERT(nbytes > 0);
15923 DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes);
15924 DUK_TVAL_SET_TVAL(p, &tv_tmp);
15925 } else {
15926 /* nop: insert top to top */
15927 DUK_ASSERT(nbytes == 0);
15928 DUK_ASSERT(p == q);
15929 }
15930}
15931
15932DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) {
15933 duk_hthread *thr = (duk_hthread *) ctx;
15934 duk_tval *tv1;
15935 duk_tval *tv2;
15936 duk_tval tv_tmp;
15937
15938 DUK_ASSERT_CTX_VALID(ctx);
15939
15940 tv1 = duk_require_tval(ctx, -1);
15941 DUK_ASSERT(tv1 != NULL);
15942 tv2 = duk_require_tval(ctx, to_index);
15943 DUK_ASSERT(tv2 != NULL);
15944
15945 /* For tv1 == tv2, both pointing to stack top, the end result
15946 * is same as duk_pop(ctx).
15947 */
15948 DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
15949 DUK_TVAL_SET_TVAL(tv2, tv1);
15950 DUK_TVAL_SET_UNDEFINED(tv1);
15951 thr->valstack_top--;
15952 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
15953}
15954
15955DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index) {
15956 duk_hthread *thr = (duk_hthread *) ctx;
15957 duk_tval *tv1;
15958 duk_tval *tv2;
15959
15960 DUK_ASSERT_CTX_VALID(ctx);
15961 DUK_UNREF(thr); /* w/o refcounting */
15962
15963 tv1 = duk_require_tval(ctx, from_index);
15964 DUK_ASSERT(tv1 != NULL);
15965 tv2 = duk_require_tval(ctx, to_index);
15966 DUK_ASSERT(tv2 != NULL);
15967
15968 /* For tv1 == tv2, this is a no-op (no explicit check needed). */
15969 DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
15970}
15971
15972DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
15973 duk_hthread *thr = (duk_hthread *) ctx;
15974 duk_tval *p;
15975 duk_tval *q;
15976#ifdef DUK_USE_REFERENCE_COUNTING
15977 duk_tval tv_tmp;
15978#endif
15979 duk_size_t nbytes;
15980
15981 DUK_ASSERT_CTX_VALID(ctx);
15982
15983 p = duk_require_tval(ctx, index);
15984 DUK_ASSERT(p != NULL);
15985 q = duk_require_tval(ctx, -1);
15986 DUK_ASSERT(q != NULL);
15987
15988 DUK_ASSERT(q >= p);
15989
15990 /* nbytes zero size case
15991 * <--------->
15992 * [ ... | p | x | x | q ] [ ... | p==q ]
15993 * => [ ... | x | x | q ] [ ... ]
15994 */
15995
15996#ifdef DUK_USE_REFERENCE_COUNTING
15997 /* use a temp: decref only when valstack reachable values are correct */
15998 DUK_TVAL_SET_TVAL(&tv_tmp, p);
15999#endif
16000
16001 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
16002 DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */
16003
16004 DUK_TVAL_SET_UNDEFINED(q);
16005 thr->valstack_top--;
16006
16007#ifdef DUK_USE_REFERENCE_COUNTING
16008 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
16009#endif
16010}
16011
16012/*
16013 * Stack slice primitives
16014 */
16015
16016DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) {
16017 duk_hthread *to_thr = (duk_hthread *) to_ctx;
16018 duk_hthread *from_thr = (duk_hthread *) from_ctx;
16019 void *src;
16020 duk_size_t nbytes;
16021 duk_tval *p;
16022 duk_tval *q;
16023
16024 /* XXX: several pointer comparison issues here */
16025
16026 DUK_ASSERT_CTX_VALID(to_ctx);
16027 DUK_ASSERT_CTX_VALID(from_ctx);
16028 DUK_ASSERT(to_ctx != NULL);
16029 DUK_ASSERT(from_ctx != NULL);
16030
16031 if (to_ctx == from_ctx) {
16032 DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT);
16033 return;
16034 }
16035 if ((count < 0) ||
16036 (count > (duk_idx_t) to_thr->valstack_max)) {
16037 /* Maximum value check ensures 'nbytes' won't wrap below. */
16038 DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
16039 return;
16040 }
16041
16042 nbytes = sizeof(duk_tval) * count;
16043 if (nbytes == 0) {
16044 return;
16045 }
16046 DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
16047 if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) {
16048 DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
16049 }
16050 src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
16051 if (src < (void *) from_thr->valstack_bottom) {
16052 DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
16053 }
16054
16055 /* copy values (no overlap even if to_ctx == from_ctx; that's not
16056 * allowed now anyway)
16057 */
16058 DUK_ASSERT(nbytes > 0);
16059 DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
16060
16061 p = to_thr->valstack_top;
16062 to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
16063
16064 if (is_copy) {
16065 /* Incref copies, keep originals. */
16066 q = to_thr->valstack_top;
16067 while (p < q) {
16068 DUK_TVAL_INCREF(to_thr, p); /* no side effects */
16069 p++;
16070 }
16071 } else {
16072 /* No net refcount change. */
16073 p = from_thr->valstack_top;
16074 q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes);
16075 from_thr->valstack_top = q;
16076
16077 while (p > q) {
16078 p--;
16079 DUK_TVAL_SET_UNDEFINED(p);
16080 /* XXX: fast primitive to set a bunch of values to UNDEFINED */
16081 }
16082 }
16083}
16084
16085/*
16086 * Get/require
16087 */
16088
16089DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) {
16090 duk_hthread *thr = (duk_hthread *) ctx;
16091 duk_tval *tv;
16092
16093 DUK_ASSERT_CTX_VALID(ctx);
16094
16095 tv = duk_get_tval(ctx, index);
16096 if (tv && DUK_TVAL_IS_UNDEFINED(tv)) {
16097 return;
16098 }
16099 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED);
16100 return; /* not reachable */
16101}
16102
16103DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) {
16104 duk_hthread *thr = (duk_hthread *) ctx;
16105 duk_tval *tv;
16106
16107 DUK_ASSERT_CTX_VALID(ctx);
16108
16109 tv = duk_get_tval(ctx, index);
16110 if (tv && DUK_TVAL_IS_NULL(tv)) {
16111 return;
16112 }
16113 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL);
16114 return; /* not reachable */
16115}
16116
16117DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) {
16118 duk_bool_t ret = 0; /* default: false */
16119 duk_tval *tv;
16120
16121 DUK_ASSERT_CTX_VALID(ctx);
16122
16123 tv = duk_get_tval(ctx, index);
16124 if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
16125 ret = DUK_TVAL_GET_BOOLEAN(tv);
16126 }
16127
16128 DUK_ASSERT(ret == 0 || ret == 1);
16129 return ret;
16130}
16131
16132DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) {
16133 duk_hthread *thr = (duk_hthread *) ctx;
16134 duk_tval *tv;
16135
16136 DUK_ASSERT_CTX_VALID(ctx);
16137
16138 tv = duk_get_tval(ctx, index);
16139 if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
16140 duk_bool_t ret = DUK_TVAL_GET_BOOLEAN(tv);
16141 DUK_ASSERT(ret == 0 || ret == 1);
16142 return ret;
16143 }
16144 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN);
16145 return 0; /* not reachable */
16146}
16147
16148DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index) {
16149 duk_double_union ret;
16150 duk_tval *tv;
16151
16152 DUK_ASSERT_CTX_VALID(ctx);
16153
16154 ret.d = DUK_DOUBLE_NAN; /* default: NaN */
16155 tv = duk_get_tval(ctx, index);
16156 if (tv && DUK_TVAL_IS_NUMBER(tv)) {
16157 ret.d = DUK_TVAL_GET_NUMBER(tv);
16158 }
16159
16160 /*
16161 * Number should already be in NaN-normalized form, but let's
16162 * normalize anyway.
16163 */
16164
16165 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
16166 return ret.d;
16167}
16168
16169DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) {
16170 duk_hthread *thr = (duk_hthread *) ctx;
16171 duk_tval *tv;
16172
16173 DUK_ASSERT_CTX_VALID(ctx);
16174
16175 tv = duk_get_tval(ctx, index);
16176 if (tv && DUK_TVAL_IS_NUMBER(tv)) {
16177 duk_double_union ret;
16178 ret.d = DUK_TVAL_GET_NUMBER(tv);
16179
16180 /*
16181 * Number should already be in NaN-normalized form,
16182 * but let's normalize anyway.
16183 */
16184
16185 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
16186 return ret.d;
16187 }
16188 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
16189 return DUK_DOUBLE_NAN; /* not reachable */
16190}
16191
16192DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index) {
16193 /* Custom coercion for API */
16194 DUK_ASSERT_CTX_VALID(ctx);
16195 return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
16196}
16197
16198DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index) {
16199 /* Custom coercion for API */
16200 DUK_ASSERT_CTX_VALID(ctx);
16201 return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
16202}
16203
16204DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index) {
16205 /* Custom coercion for API */
16206 DUK_ASSERT_CTX_VALID(ctx);
16207 return (duk_int_t) duk__api_coerce_d2i(ctx, index, 1 /*require*/);
16208}
16209
16210DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index) {
16211 /* Custom coercion for API */
16212 DUK_ASSERT_CTX_VALID(ctx);
16213 return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 1 /*require*/);
16214}
16215
16216DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
16217 const char *ret;
16218 duk_tval *tv;
16219
16220 DUK_ASSERT_CTX_VALID(ctx);
16221
16222 /* default: NULL, length 0 */
16223 ret = NULL;
16224 if (out_len) {
16225 *out_len = 0;
16226 }
16227
16228 tv = duk_get_tval(ctx, index);
16229 if (tv && DUK_TVAL_IS_STRING(tv)) {
16230 /* Here we rely on duk_hstring instances always being zero
16231 * terminated even if the actual string is not.
16232 */
16233 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
16234 DUK_ASSERT(h != NULL);
16235 ret = (const char *) DUK_HSTRING_GET_DATA(h);
16236 if (out_len) {
16237 *out_len = DUK_HSTRING_GET_BYTELEN(h);
16238 }
16239 }
16240
16241 return ret;
16242}
16243
16244DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
16245 duk_hthread *thr = (duk_hthread *) ctx;
16246 const char *ret;
16247
16248 DUK_ASSERT_CTX_VALID(ctx);
16249
16250 /* Note: this check relies on the fact that even a zero-size string
16251 * has a non-NULL pointer.
16252 */
16253 ret = duk_get_lstring(ctx, index, out_len);
16254 if (ret) {
16255 return ret;
16256 }
16257 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING);
16258 return NULL; /* not reachable */
16259}
16260
16261DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t index) {
16262 DUK_ASSERT_CTX_VALID(ctx);
16263
16264 return duk_get_lstring(ctx, index, NULL);
16265}
16266
16267DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t index) {
16268 DUK_ASSERT_CTX_VALID(ctx);
16269
16270 return duk_require_lstring(ctx, index, NULL);
16271}
16272
16273DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t index) {
16274 duk_tval *tv;
16275
16276 DUK_ASSERT_CTX_VALID(ctx);
16277
16278 tv = duk_get_tval(ctx, index);
16279 if (tv && DUK_TVAL_IS_POINTER(tv)) {
16280 void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
16281 return (void *) p;
16282 }
16283
16284 return NULL;
16285}
16286
16287DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) {
16288 duk_hthread *thr = (duk_hthread *) ctx;
16289 duk_tval *tv;
16290
16291 DUK_ASSERT_CTX_VALID(ctx);
16292
16293 /* Note: here we must be wary of the fact that a pointer may be
16294 * valid and be a NULL.
16295 */
16296 tv = duk_get_tval(ctx, index);
16297 if (tv && DUK_TVAL_IS_POINTER(tv)) {
16298 void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
16299 return (void *) p;
16300 }
16301 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER);
16302 return NULL; /* not reachable */
16303}
16304
16305#if 0 /*unused*/
16306DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index) {
16307 duk_tval *tv;
16308
16309 DUK_ASSERT_CTX_VALID(ctx);
16310
16311 tv = duk_get_tval(ctx, index);
16312 if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
16313 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
16314 DUK_ASSERT(h != NULL);
16315 return (void *) h;
16316 }
16317
16318 return NULL;
16319}
16320#endif
16321
16322DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
16323 duk_hthread *thr = (duk_hthread *) ctx;
16324 duk_tval *tv;
16325
16326 DUK_ASSERT_CTX_VALID(ctx);
16327 DUK_UNREF(thr);
16328
16329 if (out_size != NULL) {
16330 *out_size = 0;
16331 }
16332
16333 tv = duk_get_tval(ctx, index);
16334 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
16335 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
16336 DUK_ASSERT(h != NULL);
16337 if (out_size) {
16338 *out_size = DUK_HBUFFER_GET_SIZE(h);
16339 }
16340 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
16341 }
16342
16343 if (throw_flag) {
16344 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
16345 }
16346 return NULL;
16347}
16348
16349DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16350 return duk__get_buffer_helper(ctx, index, out_size, 0 /*throw_flag*/);
16351}
16352
16353DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16354 return duk__get_buffer_helper(ctx, index, out_size, 1 /*throw_flag*/);
16355}
16356
16357DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
16358 duk_hthread *thr = (duk_hthread *) ctx;
16359 duk_tval *tv;
16360
16361 DUK_ASSERT_CTX_VALID(ctx);
16362 DUK_UNREF(thr);
16363
16364 if (out_size != NULL) {
16365 *out_size = 0;
16366 }
16367
16368 tv = duk_get_tval(ctx, index);
16369 if (tv == NULL) {
16370 goto fail;
16371 }
16372
16373 if (DUK_TVAL_IS_BUFFER(tv)) {
16374 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
16375 DUK_ASSERT(h != NULL);
16376 if (out_size) {
16377 *out_size = DUK_HBUFFER_GET_SIZE(h);
16378 }
16379 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
16380 } else if (DUK_TVAL_IS_OBJECT(tv)) {
16381 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
16382 DUK_ASSERT(h != NULL);
16383 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
16384 /* XXX: this is probably a useful shared helper: for a
16385 * duk_hbufferobject, get a validated buffer pointer/length.
16386 */
16387 duk_hbufferobject *h_bufobj = (duk_hbufferobject *) h;
16388 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
16389
16390 if (h_bufobj->buf != NULL &&
16391 DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
16392 duk_uint8_t *p;
16393
16394 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
16395 if (out_size != NULL) {
16396 *out_size = (duk_size_t) h_bufobj->length;
16397 }
16398 return (void *) (p + h_bufobj->offset);
16399 }
16400 /* if slice not fully valid, treat as error */
16401 }
16402 }
16403
16404 fail:
16405 if (throw_flag) {
16406 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
16407 }
16408 return NULL;
16409}
16410
16411DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16412 return duk__get_buffer_data_helper(ctx, index, out_size, 0 /*throw_flag*/);
16413}
16414
16415DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16416 return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/);
16417}
16418
16419/* Raw helper for getting a value from the stack, checking its tag.
16420 * The tag cannot be a number because numbers don't have an internal
16421 * tag in the packed representation.
16422 */
16423
16424DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) {
16425 duk_tval *tv;
16426
16427 DUK_ASSERT_CTX_VALID(ctx);
16428
16429 tv = duk_get_tval(ctx, index);
16430 if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) {
16431 duk_heaphdr *ret;
16432 ret = DUK_TVAL_GET_HEAPHDR(tv);
16433 DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
16434 return ret;
16435 }
16436
16437 return (duk_heaphdr *) NULL;
16438}
16439
16440DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) {
16441 return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
16442}
16443
16444DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) {
16445 duk_heaphdr *h;
16446 h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
16447 if (h == NULL) {
16448 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING);
16449 }
16450 return (duk_hstring *) h;
16451}
16452
16453DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) {
16454 return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16455}
16456
16457DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) {
16458 duk_heaphdr *h;
16459 h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16460 if (h == NULL) {
16461 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT);
16462 }
16463 return (duk_hobject *) h;
16464}
16465
16466DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) {
16467 return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
16468}
16469
16470DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) {
16471 duk_heaphdr *h;
16472 h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
16473 if (h == NULL) {
16474 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER);
16475 }
16476 return (duk_hbuffer *) h;
16477}
16478
16479DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) {
16480 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16481 if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
16482 h = NULL;
16483 }
16484 return (duk_hthread *) h;
16485}
16486
16487DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) {
16488 duk_hthread *thr = (duk_hthread *) ctx;
16489 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16490 if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) {
16491 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD);
16492 }
16493 return (duk_hthread *) h;
16494}
16495
16496DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
16497 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16498 if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
16499 h = NULL;
16500 }
16501 return (duk_hcompiledfunction *) h;
16502}
16503
16504DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
16505 duk_hthread *thr = (duk_hthread *) ctx;
16506 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16507 if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) {
16508 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION);
16509 }
16510 return (duk_hcompiledfunction *) h;
16511}
16512
16513DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) {
16514 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16515 if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
16516 h = NULL;
16517 }
16518 return (duk_hnativefunction *) h;
16519}
16520
16521DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) {
16522 duk_hthread *thr = (duk_hthread *) ctx;
16523 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16524 if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) {
16525 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
16526 }
16527 return (duk_hnativefunction *) h;
16528}
16529
16530DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index) {
16531 duk_tval *tv;
16532 duk_hobject *h;
16533 duk_hnativefunction *f;
16534
16535 DUK_ASSERT_CTX_VALID(ctx);
16536
16537 tv = duk_get_tval(ctx, index);
16538 if (!tv) {
16539 return NULL;
16540 }
16541 if (!DUK_TVAL_IS_OBJECT(tv)) {
16542 return NULL;
16543 }
16544 h = DUK_TVAL_GET_OBJECT(tv);
16545 DUK_ASSERT(h != NULL);
16546
16547 if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
16548 return NULL;
16549 }
16550 DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h));
16551 f = (duk_hnativefunction *) h;
16552
16553 return f->func;
16554}
16555
16556DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index) {
16557 duk_hthread *thr = (duk_hthread *) ctx;
16558 duk_c_function ret;
16559
16560 DUK_ASSERT_CTX_VALID(ctx);
16561
16562 ret = duk_get_c_function(ctx, index);
16563 if (!ret) {
16564 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
16565 }
16566 return ret;
16567}
16568
16569DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) {
16570 if (!duk_is_function(ctx, index)) {
16571 DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION);
16572 }
16573}
16574
16575DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) {
16576 DUK_ASSERT_CTX_VALID(ctx);
16577
16578 return (duk_context *) duk_get_hthread(ctx, index);
16579}
16580
16581DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index) {
16582 DUK_ASSERT_CTX_VALID(ctx);
16583
16584 return (duk_context *) duk_require_hthread(ctx, index);
16585}
16586
16587DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index) {
16588 duk_tval *tv;
16589 void *ret;
16590
16591 DUK_ASSERT_CTX_VALID(ctx);
16592
16593 tv = duk_get_tval(ctx, index);
16594 if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
16595 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
16596 DUK_ASSERT(ret != NULL);
16597 return ret;
16598 }
16599
16600 return (void *) NULL;
16601}
16602
16603DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) {
16604 duk_hthread *thr = (duk_hthread *) ctx;
16605 duk_tval *tv;
16606 void *ret;
16607
16608 DUK_ASSERT_CTX_VALID(ctx);
16609
16610 tv = duk_require_tval(ctx, index);
16611 DUK_ASSERT(tv != NULL);
16612 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
16613 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
16614 DUK_ASSERT(ret != NULL);
16615 return ret;
16616 }
16617
16618 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE);
16619 return (void *) NULL; /* not reachable */
16620}
16621
16622#if 0
16623/* This would be pointless: we'd return NULL for both lightfuncs and
16624 * unexpected types.
16625 */
16626DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
16627}
16628#endif
16629
16630/* Useful for internal call sites where we either expect an object (function)
16631 * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
16632 * to an object). Return value is NULL if value is neither an object nor a
16633 * lightfunc.
16634 */
16635DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
16636 duk_tval *tv;
16637
16638 DUK_ASSERT_CTX_VALID(ctx);
16639
16640 tv = duk_require_tval(ctx, index);
16641 DUK_ASSERT(tv != NULL);
16642 if (DUK_TVAL_IS_OBJECT(tv)) {
16643 return DUK_TVAL_GET_OBJECT(tv);
16644 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
16645 duk_to_object(ctx, index);
16646 return duk_require_hobject(ctx, index);
16647 }
16648
16649 return NULL;
16650}
16651
16652/* Useful for internal call sites where we either expect an object (function)
16653 * or a lightfunc. Returns NULL for a lightfunc.
16654 */
16655DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
16656 duk_hthread *thr = (duk_hthread *) ctx;
16657 duk_tval *tv;
16658
16659 DUK_ASSERT_CTX_VALID(ctx);
16660
16661 tv = duk_require_tval(ctx, index);
16662 DUK_ASSERT(tv != NULL);
16663 if (DUK_TVAL_IS_OBJECT(tv)) {
16664 return DUK_TVAL_GET_OBJECT(tv);
16665 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
16666 return NULL;
16667 }
16668 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
16669 return NULL; /* not reachable */
16670}
16671
16672/* Useful for internal call sites where we either expect an object (function)
16673 * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
16674 * to an object). Return value is never NULL.
16675 */
16676DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
16677 duk_hthread *thr = (duk_hthread *) ctx;
16678 duk_tval *tv;
16679
16680 DUK_ASSERT_CTX_VALID(ctx);
16681
16682 tv = duk_require_tval(ctx, index);
16683 if (DUK_TVAL_IS_OBJECT(tv)) {
16684 return DUK_TVAL_GET_OBJECT(tv);
16685 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
16686 duk_to_object(ctx, index);
16687 return duk_require_hobject(ctx, index);
16688 }
16689 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
16690 return NULL; /* not reachable */
16691}
16692
16693DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
16694 duk_hobject *h;
16695
16696 DUK_ASSERT_CTX_VALID(ctx);
16697 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
16698 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
16699
16700 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16701 if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) {
16702 h = NULL;
16703 }
16704 return h;
16705}
16706
16707DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
16708 duk_hthread *thr;
16709 duk_hobject *h;
16710
16711 DUK_ASSERT_CTX_VALID(ctx);
16712 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
16713 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
16714 thr = (duk_hthread *) ctx;
16715
16716 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16717 if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) {
16718 duk_hstring *h_class;
16719 h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
16720 DUK_UNREF(h_class);
16721
16722 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
16723 }
16724 return h;
16725}
16726
16727DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
16728 duk_tval *tv;
16729
16730 DUK_ASSERT_CTX_VALID(ctx);
16731
16732 tv = duk_get_tval(ctx, index);
16733 if (!tv) {
16734 return 0;
16735 }
16736
16737 switch (DUK_TVAL_GET_TAG(tv)) {
16738 case DUK_TAG_UNDEFINED:
16739 case DUK_TAG_NULL:
16740 case DUK_TAG_BOOLEAN:
16741 case DUK_TAG_POINTER:
16742 return 0;
16743 case DUK_TAG_STRING: {
16744 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
16745 DUK_ASSERT(h != NULL);
16746 return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
16747 }
16748 case DUK_TAG_OBJECT: {
16749 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
16750 DUK_ASSERT(h != NULL);
16751 return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
16752 }
16753 case DUK_TAG_BUFFER: {
16754 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
16755 DUK_ASSERT(h != NULL);
16756 return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
16757 }
16758 case DUK_TAG_LIGHTFUNC: {
16759 duk_small_uint_t lf_flags;
16760 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
16761 return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
16762 }
16763#if defined(DUK_USE_FASTINT)
16764 case DUK_TAG_FASTINT:
16765#endif
16766 default:
16767 /* number */
16768 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
16769 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
16770 return 0;
16771 }
16772
16773 DUK_UNREACHABLE();
16774}
16775
16776DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length) {
16777 duk_hthread *thr = (duk_hthread *) ctx;
16778 duk_hobject *h;
16779
16780 DUK_ASSERT_CTX_VALID(ctx);
16781
16782 h = duk_get_hobject(ctx, index);
16783 if (!h) {
16784 return;
16785 }
16786
16787 duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */
16788}
16789
16790/*
16791 * Conversions and coercions
16792 *
16793 * The conversion/coercions are in-place operations on the value stack.
16794 * Some operations are implemented here directly, while others call a
16795 * helper in duk_js_ops.c after validating arguments.
16796 */
16797
16798/* E5 Section 8.12.8 */
16799
16800DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t index, duk_small_int_t func_stridx) {
16801 if (duk_get_prop_stridx(ctx, index, func_stridx)) {
16802 /* [ ... func ] */
16803 if (duk_is_callable(ctx, -1)) {
16804 duk_dup(ctx, index); /* -> [ ... func this ] */
16805 duk_call_method(ctx, 0); /* -> [ ... retval ] */
16806 if (duk_is_primitive(ctx, -1)) {
16807 duk_replace(ctx, index);
16808 return 1;
16809 }
16810 /* [ ... retval ]; popped below */
16811 }
16812 }
16813 duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */
16814 return 0;
16815}
16816
16817DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
16818 duk_hthread *thr = (duk_hthread *) ctx;
16819 duk_hobject *obj;
16820 /* inline initializer for coercers[] is not allowed by old compilers like BCC */
16821 duk_small_int_t coercers[2];
16822
16823 DUK_ASSERT_CTX_VALID(ctx);
16824 DUK_ASSERT(thr != NULL);
16825
16826 coercers[0] = DUK_STRIDX_VALUE_OF;
16827 coercers[1] = DUK_STRIDX_TO_STRING;
16828
16829 index = duk_require_normalize_index(ctx, index);
16830 obj = duk_require_hobject_or_lfunc(ctx, index);
16831
16832 if (hint == DUK_HINT_NONE) {
16833 if (obj != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) {
16834 hint = DUK_HINT_STRING;
16835 } else {
16836 hint = DUK_HINT_NUMBER;
16837 }
16838 }
16839
16840 if (hint == DUK_HINT_STRING) {
16841 coercers[0] = DUK_STRIDX_TO_STRING;
16842 coercers[1] = DUK_STRIDX_VALUE_OF;
16843 }
16844
16845 if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) {
16846 return;
16847 }
16848
16849 if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) {
16850 return;
16851 }
16852
16853 DUK_ERROR_TYPE(thr, DUK_STR_DEFAULTVALUE_COERCE_FAILED);
16854}
16855
16856DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t index) {
16857 duk_hthread *thr = (duk_hthread *) ctx;
16858 duk_tval *tv;
16859
16860 DUK_ASSERT_CTX_VALID(ctx);
16861 DUK_UNREF(thr);
16862
16863 tv = duk_require_tval(ctx, index);
16864 DUK_ASSERT(tv != NULL);
16865 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
16866}
16867
16868DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t index) {
16869 duk_hthread *thr = (duk_hthread *) ctx;
16870 duk_tval *tv;
16871
16872 DUK_ASSERT_CTX_VALID(ctx);
16873 DUK_UNREF(thr);
16874
16875 tv = duk_require_tval(ctx, index);
16876 DUK_ASSERT(tv != NULL);
16877 DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
16878}
16879
16880/* E5 Section 9.1 */
16881DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
16882 DUK_ASSERT_CTX_VALID(ctx);
16883 DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
16884
16885 index = duk_require_normalize_index(ctx, index);
16886
16887 if (!duk_check_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT |
16888 DUK_TYPE_MASK_LIGHTFUNC)) {
16889 /* everything except object stay as is */
16890 return;
16891 }
16892 duk_to_defaultvalue(ctx, index, hint);
16893}
16894
16895/* E5 Section 9.2 */
16896DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) {
16897 duk_hthread *thr = (duk_hthread *) ctx;
16898 duk_tval *tv;
16899 duk_bool_t val;
16900
16901 DUK_ASSERT_CTX_VALID(ctx);
16902 DUK_UNREF(thr);
16903
16904 index = duk_require_normalize_index(ctx, index);
16905
16906 tv = duk_require_tval(ctx, index);
16907 DUK_ASSERT(tv != NULL);
16908
16909 val = duk_js_toboolean(tv);
16910 DUK_ASSERT(val == 0 || val == 1);
16911
16912 /* Note: no need to re-lookup tv, conversion is side effect free */
16913 DUK_ASSERT(tv != NULL);
16914 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */
16915 return val;
16916}
16917
16918DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index) {
16919 duk_hthread *thr = (duk_hthread *) ctx;
16920 duk_tval *tv;
16921 duk_double_t d;
16922
16923 DUK_ASSERT_CTX_VALID(ctx);
16924
16925 tv = duk_require_tval(ctx, index);
16926 DUK_ASSERT(tv != NULL);
16927 /* XXX: fastint? */
16928 d = duk_js_tonumber(thr, tv);
16929
16930 /* Note: need to re-lookup because ToNumber() may have side effects */
16931 tv = duk_require_tval(ctx, index);
16932 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
16933 return d;
16934}
16935
16936/* XXX: combine all the integer conversions: they share everything
16937 * but the helper function for coercion.
16938 */
16939
16940typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
16941
16942DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t index, duk__toint_coercer coerce_func) {
16943 duk_hthread *thr = (duk_hthread *) ctx;
16944 duk_tval *tv;
16945 duk_double_t d;
16946
16947 DUK_ASSERT_CTX_VALID(ctx);
16948
16949 tv = duk_require_tval(ctx, index);
16950 DUK_ASSERT(tv != NULL);
16951 d = coerce_func(thr, tv);
16952
16953 /* XXX: fastint? */
16954
16955 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
16956 tv = duk_require_tval(ctx, index);
16957 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
16958 return d;
16959}
16960
16961DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index) {
16962 /* Value coercion (in stack): ToInteger(), E5 Section 9.4
16963 * API return value coercion: custom
16964 */
16965 DUK_ASSERT_CTX_VALID(ctx);
16966 (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
16967 return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
16968}
16969
16970DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index) {
16971 /* Value coercion (in stack): ToInteger(), E5 Section 9.4
16972 * API return value coercion: custom
16973 */
16974 DUK_ASSERT_CTX_VALID(ctx);
16975 (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
16976 return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
16977}
16978
16979DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index) {
16980 duk_hthread *thr = (duk_hthread *) ctx;
16981 duk_tval *tv;
16982 duk_int32_t ret;
16983
16984 DUK_ASSERT_CTX_VALID(ctx);
16985
16986 tv = duk_require_tval(ctx, index);
16987 DUK_ASSERT(tv != NULL);
16988 ret = duk_js_toint32(thr, tv);
16989
16990 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
16991 tv = duk_require_tval(ctx, index);
16992 DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv, ret); /* side effects */
16993 return ret;
16994}
16995
16996DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index) {
16997 duk_hthread *thr = (duk_hthread *) ctx;
16998 duk_tval *tv;
16999 duk_uint32_t ret;
17000
17001 DUK_ASSERT_CTX_VALID(ctx);
17002
17003 tv = duk_require_tval(ctx, index);
17004 DUK_ASSERT(tv != NULL);
17005 ret = duk_js_touint32(thr, tv);
17006
17007 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
17008 tv = duk_require_tval(ctx, index);
17009 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
17010 return ret;
17011}
17012
17013DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index) {
17014 duk_hthread *thr = (duk_hthread *) ctx;
17015 duk_tval *tv;
17016 duk_uint16_t ret;
17017
17018 DUK_ASSERT_CTX_VALID(ctx);
17019
17020 tv = duk_require_tval(ctx, index);
17021 DUK_ASSERT(tv != NULL);
17022 ret = duk_js_touint16(thr, tv);
17023
17024 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
17025 tv = duk_require_tval(ctx, index);
17026 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
17027 return ret;
17028}
17029
17030#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
17031/* Special coercion for Uint8ClampedArray. */
17032DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) {
17033 duk_double_t d;
17034 duk_double_t t;
17035 duk_uint8_t ret;
17036
17037 /* XXX: Simplify this algorithm, should be possible to come up with
17038 * a shorter and faster algorithm by inspecting IEEE representation
17039 * directly.
17040 */
17041
17042 d = duk_to_number(ctx, index);
17043 if (d <= 0.0) {
17044 return 0;
17045 } else if (d >= 255) {
17046 return 255;
17047 } else if (DUK_ISNAN(d)) {
17048 /* Avoid NaN-to-integer coercion as it is compiler specific. */
17049 return 0;
17050 }
17051
17052 t = d - DUK_FLOOR(d);
17053 if (t == 0.5) {
17054 /* Exact halfway, round to even. */
17055 ret = (duk_uint8_t) d;
17056 ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4
17057 * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4
17058 */
17059 } else {
17060 /* Not halfway, round to nearest. */
17061 ret = (duk_uint8_t) (d + 0.5);
17062 }
17063 return ret;
17064}
17065#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
17066
17067DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
17068 DUK_ASSERT_CTX_VALID(ctx);
17069
17070 (void) duk_to_string(ctx, index);
17071 return duk_require_lstring(ctx, index, out_len);
17072}
17073
17074DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx) {
17075 DUK_ASSERT_CTX_VALID(ctx);
17076
17077 duk_to_string(ctx, -1);
17078 return 1;
17079}
17080
17081DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
17082 DUK_ASSERT_CTX_VALID(ctx);
17083
17084 index = duk_require_normalize_index(ctx, index);
17085
17086 /* We intentionally ignore the duk_safe_call() return value and only
17087 * check the output type. This way we don't also need to check that
17088 * the returned value is indeed a string in the success case.
17089 */
17090
17091 duk_dup(ctx, index);
17092 (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
17093 if (!duk_is_string(ctx, -1)) {
17094 /* Error: try coercing error to string once. */
17095 (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
17096 if (!duk_is_string(ctx, -1)) {
17097 /* Double error */
17098 duk_pop(ctx);
17099 duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
17100 } else {
17101 ;
17102 }
17103 } else {
17104 ;
17105 }
17106 DUK_ASSERT(duk_is_string(ctx, -1));
17107 DUK_ASSERT(duk_get_string(ctx, -1) != NULL);
17108
17109 duk_replace(ctx, index);
17110 return duk_get_lstring(ctx, index, out_len);
17111}
17112
17113#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
17114DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) {
17115 (void) duk_safe_to_string(ctx, index);
17116 DUK_ASSERT(duk_is_string(ctx, index));
17117 DUK_ASSERT(duk_get_hstring(ctx, index) != NULL);
17118 return duk_get_hstring(ctx, index);
17119}
17120#endif
17121
17122/* Coerce top into Object.prototype.toString() output. */
17123DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) {
17124 duk_hthread *thr;
17125 duk_uint_t typemask;
17126 duk_hstring *h_strclass;
17127
17128 DUK_ASSERT_CTX_VALID(ctx);
17129 thr = (duk_hthread *) ctx;
17130 DUK_UNREF(thr);
17131
17132 typemask = duk_get_type_mask(ctx, -1);
17133 if (typemask & DUK_TYPE_MASK_UNDEFINED) {
17134 h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr);
17135 } else if (typemask & DUK_TYPE_MASK_NULL) {
17136 h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr);
17137 } else {
17138 duk_hobject *h_obj;
17139
17140 duk_to_object(ctx, -1);
17141 h_obj = duk_get_hobject(ctx, -1);
17142 DUK_ASSERT(h_obj != NULL);
17143
17144 h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj);
17145 }
17146 DUK_ASSERT(h_strclass != NULL);
17147
17148 duk_pop(ctx);
17149 duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
17150}
17151
17152#if !defined(DUK_USE_PARANOID_ERRORS)
17153DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) {
17154 duk_hthread *thr;
17155 duk_hstring *h_strclass;
17156
17157 DUK_ASSERT_CTX_VALID(ctx);
17158 DUK_ASSERT(h != NULL);
17159 thr = (duk_hthread *) ctx;
17160 DUK_UNREF(thr);
17161
17162 h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h);
17163 DUK_ASSERT(h_strclass != NULL);
17164 duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
17165}
17166#endif /* !DUK_USE_PARANOID_ERRORS */
17167
17168/* XXX: other variants like uint, u32 etc */
17169DUK_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) {
17170 duk_hthread *thr = (duk_hthread *) ctx;
17171 duk_tval *tv;
17172 duk_tval tv_tmp;
17173 duk_double_t d, dmin, dmax;
17174 duk_int_t res;
17175 duk_bool_t clamped = 0;
17176
17177 DUK_ASSERT_CTX_VALID(ctx);
17178
17179 tv = duk_require_tval(ctx, index);
17180 DUK_ASSERT(tv != NULL);
17181 d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
17182
17183 dmin = (duk_double_t) minval;
17184 dmax = (duk_double_t) maxval;
17185
17186 if (d < dmin) {
17187 clamped = 1;
17188 res = minval;
17189 d = dmin;
17190 } else if (d > dmax) {
17191 clamped = 1;
17192 res = maxval;
17193 d = dmax;
17194 } else {
17195 res = (duk_int_t) d;
17196 }
17197 DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */
17198 /* 'd' and 'res' agree here */
17199
17200 /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
17201 tv = duk_get_tval(ctx, index);
17202 DUK_ASSERT(tv != NULL); /* not popped by side effect */
17203 DUK_TVAL_SET_TVAL(&tv_tmp, tv);
17204#if defined(DUK_USE_FASTINT)
17205#if (DUK_INT_MAX <= 0x7fffffffL)
17206 DUK_TVAL_SET_FASTINT_I32(tv, res);
17207#else
17208 /* Clamping needed if duk_int_t is 64 bits. */
17209 if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
17210 DUK_TVAL_SET_FASTINT(tv, res);
17211 } else {
17212 DUK_TVAL_SET_NUMBER(tv, d);
17213 }
17214#endif
17215#else
17216 DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */
17217#endif
17218 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
17219
17220 if (out_clamped) {
17221 *out_clamped = clamped;
17222 } else {
17223 /* coerced value is updated to value stack even when RangeError thrown */
17224 if (clamped) {
17225 DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE);
17226 }
17227 }
17228
17229 return res;
17230}
17231
17232DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_idx_t minval, duk_idx_t maxval) {
17233 duk_bool_t dummy;
17234 return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy);
17235}
17236
17237DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval) {
17238 return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
17239}
17240
17241DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
17242 duk_hthread *thr = (duk_hthread *) ctx;
17243 duk_tval *tv;
17244
17245 DUK_ASSERT_CTX_VALID(ctx);
17246 DUK_UNREF(thr);
17247
17248 index = duk_require_normalize_index(ctx, index);
17249
17250 tv = duk_require_tval(ctx, index);
17251 DUK_ASSERT(tv != NULL);
17252
17253 switch (DUK_TVAL_GET_TAG(tv)) {
17254 case DUK_TAG_UNDEFINED: {
17255 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
17256 break;
17257 }
17258 case DUK_TAG_NULL: {
17259 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
17260 break;
17261 }
17262 case DUK_TAG_BOOLEAN: {
17263 if (DUK_TVAL_GET_BOOLEAN(tv)) {
17264 duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
17265 } else {
17266 duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
17267 }
17268 break;
17269 }
17270 case DUK_TAG_STRING: {
17271 /* nop */
17272 goto skip_replace;
17273 }
17274 case DUK_TAG_OBJECT: {
17275 duk_to_primitive(ctx, index, DUK_HINT_STRING);
17276 return duk_to_string(ctx, index); /* Note: recursive call */
17277 }
17278 case DUK_TAG_BUFFER: {
17279 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17280
17281 /* Note: this allows creation of internal strings. */
17282
17283 DUK_ASSERT(h != NULL);
17284 duk_push_lstring(ctx,
17285 (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
17286 (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
17287 break;
17288 }
17289 case DUK_TAG_POINTER: {
17290 void *ptr = DUK_TVAL_GET_POINTER(tv);
17291 if (ptr != NULL) {
17292 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr);
17293 } else {
17294 /* Represent a null pointer as 'null' to be consistent with
17295 * the JX format variant. Native '%p' format for a NULL
17296 * pointer may be e.g. '(nil)'.
17297 */
17298 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
17299 }
17300 break;
17301 }
17302 case DUK_TAG_LIGHTFUNC: {
17303 /* Should match Function.prototype.toString() */
17304 duk_push_lightfunc_tostring(ctx, tv);
17305 break;
17306 }
17307#if defined(DUK_USE_FASTINT)
17308 case DUK_TAG_FASTINT:
17309#endif
17310 default: {
17311 /* number */
17312 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
17313 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17314 duk_push_tval(ctx, tv);
17315 duk_numconv_stringify(ctx,
17316 10 /*radix*/,
17317 0 /*precision:shortest*/,
17318 0 /*force_exponential*/);
17319 break;
17320 }
17321 }
17322
17323 duk_replace(ctx, index);
17324
17325 skip_replace:
17326 return duk_require_string(ctx, index);
17327}
17328
17329DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) {
17330 duk_hstring *ret;
17331 DUK_ASSERT_CTX_VALID(ctx);
17332 duk_to_string(ctx, index);
17333 ret = duk_get_hstring(ctx, index);
17334 DUK_ASSERT(ret != NULL);
17335 return ret;
17336}
17337
17338DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t mode) {
17339 duk_hthread *thr = (duk_hthread *) ctx;
17340 duk_hbuffer *h_buf;
17341 const duk_uint8_t *src_data;
17342 duk_size_t src_size;
17343 duk_uint8_t *dst_data;
17344
17345 DUK_ASSERT_CTX_VALID(ctx);
17346 DUK_UNREF(thr);
17347
17348 index = duk_require_normalize_index(ctx, index);
17349
17350 h_buf = duk_get_hbuffer(ctx, index);
17351 if (h_buf != NULL) {
17352 /* Buffer is kept as is, with the fixed/dynamic nature of the
17353 * buffer only changed if requested. An external buffer
17354 * is converted into a non-external dynamic buffer in a
17355 * duk_to_dynamic_buffer() call.
17356 */
17357 duk_uint_t tmp;
17358 duk_uint8_t *tmp_ptr;
17359
17360 tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
17361 src_data = (const duk_uint8_t *) tmp_ptr;
17362 src_size = DUK_HBUFFER_GET_SIZE(h_buf);
17363
17364 tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED);
17365 if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) ||
17366 mode == DUK_BUF_MODE_DONTCARE) {
17367 /* Note: src_data may be NULL if input is a zero-size
17368 * dynamic buffer.
17369 */
17370 dst_data = tmp_ptr;
17371 goto skip_copy;
17372 }
17373 } else {
17374 /* Non-buffer value is first ToString() coerced, then converted
17375 * to a buffer (fixed buffer is used unless a dynamic buffer is
17376 * explicitly requested).
17377 */
17378
17379 src_data = (const duk_uint8_t *) duk_to_lstring(ctx, index, &src_size);
17380 }
17381
17382 dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
17383 if (DUK_LIKELY(src_size > 0)) {
17384 /* When src_size == 0, src_data may be NULL (if source
17385 * buffer is dynamic), and dst_data may be NULL (if
17386 * target buffer is dynamic). Avoid zero-size memcpy()
17387 * with an invalid pointer.
17388 */
17389 DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
17390 }
17391 duk_replace(ctx, index);
17392 skip_copy:
17393
17394 if (out_size) {
17395 *out_size = src_size;
17396 }
17397 return dst_data;
17398}
17399
17400DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) {
17401 duk_tval *tv;
17402 void *res;
17403
17404 DUK_ASSERT_CTX_VALID(ctx);
17405
17406 index = duk_require_normalize_index(ctx, index);
17407
17408 tv = duk_require_tval(ctx, index);
17409 DUK_ASSERT(tv != NULL);
17410
17411 switch (DUK_TVAL_GET_TAG(tv)) {
17412 case DUK_TAG_UNDEFINED:
17413 case DUK_TAG_NULL:
17414 case DUK_TAG_BOOLEAN:
17415 res = NULL;
17416 break;
17417 case DUK_TAG_POINTER:
17418 res = DUK_TVAL_GET_POINTER(tv);
17419 break;
17420 case DUK_TAG_STRING:
17421 case DUK_TAG_OBJECT:
17422 case DUK_TAG_BUFFER:
17423 /* Heap allocated: return heap pointer which is NOT useful
17424 * for the caller, except for debugging.
17425 */
17426 res = (void *) DUK_TVAL_GET_HEAPHDR(tv);
17427 break;
17428 case DUK_TAG_LIGHTFUNC:
17429 /* Function pointers do not always cast correctly to void *
17430 * (depends on memory and segmentation model for instance),
17431 * so they coerce to NULL.
17432 */
17433 res = NULL;
17434 break;
17435#if defined(DUK_USE_FASTINT)
17436 case DUK_TAG_FASTINT:
17437#endif
17438 default:
17439 /* number */
17440 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
17441 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17442 res = NULL;
17443 break;
17444 }
17445
17446 duk_push_pointer(ctx, res);
17447 duk_replace(ctx, index);
17448 return res;
17449}
17450
17451DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
17452 duk_hthread *thr = (duk_hthread *) ctx;
17453 duk_tval *tv;
17454 duk_uint_t flags = 0; /* shared flags for a subset of types */
17455 duk_small_int_t proto = 0;
17456
17457 DUK_ASSERT_CTX_VALID(ctx);
17458
17459 index = duk_require_normalize_index(ctx, index);
17460
17461 tv = duk_require_tval(ctx, index);
17462 DUK_ASSERT(tv != NULL);
17463
17464 switch (DUK_TVAL_GET_TAG(tv)) {
17465 case DUK_TAG_UNDEFINED:
17466 case DUK_TAG_NULL: {
17467 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
17468 break;
17469 }
17470 case DUK_TAG_BOOLEAN: {
17471 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17472 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
17473 proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
17474 goto create_object;
17475 }
17476 case DUK_TAG_STRING: {
17477 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17478 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
17479 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
17480 proto = DUK_BIDX_STRING_PROTOTYPE;
17481 goto create_object;
17482 }
17483 case DUK_TAG_OBJECT: {
17484 /* nop */
17485 break;
17486 }
17487 case DUK_TAG_BUFFER: {
17488 /* A plain buffer coerces to a Duktape.Buffer because it's the
17489 * object counterpart of the plain buffer value. But it might
17490 * still make more sense to produce an ArrayBuffer here?
17491 */
17492
17493 duk_hbufferobject *h_bufobj;
17494 duk_hbuffer *h_val;
17495
17496 h_val = DUK_TVAL_GET_BUFFER(tv);
17497 DUK_ASSERT(h_val != NULL);
17498
17499 h_bufobj = duk_push_bufferobject_raw(ctx,
17500 DUK_HOBJECT_FLAG_EXTENSIBLE |
17501 DUK_HOBJECT_FLAG_BUFFEROBJECT |
17502 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
17503 DUK_BIDX_BUFFER_PROTOTYPE);
17504 DUK_ASSERT(h_bufobj != NULL);
17505 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE((duk_hobject *) h_bufobj));
17506 DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj));
17507
17508 h_bufobj->buf = h_val;
17509 DUK_HBUFFER_INCREF(thr, h_val);
17510 DUK_ASSERT(h_bufobj->offset == 0);
17511 h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
17512 DUK_ASSERT(h_bufobj->shift == 0);
17513 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
17514
17515 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
17516 goto replace_value;
17517 }
17518 case DUK_TAG_POINTER: {
17519 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17520 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
17521 proto = DUK_BIDX_POINTER_PROTOTYPE;
17522 goto create_object;
17523 }
17524 case DUK_TAG_LIGHTFUNC: {
17525 /* Lightfunc coerces to a Function instance with concrete
17526 * properties. Since 'length' is virtual for Duktape/C
17527 * functions, don't need to define that.
17528 *
17529 * The result is made extensible to mimic what happens to
17530 * strings:
17531 * > Object.isExtensible(Object('foo'))
17532 * true
17533 */
17534 duk_small_uint_t lf_flags;
17535 duk_idx_t nargs;
17536 duk_small_uint_t lf_len;
17537 duk_c_function func;
17538 duk_hnativefunction *nf;
17539
17540 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
17541
17542 nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
17543 if (nargs == DUK_LFUNC_NARGS_VARARGS) {
17544 nargs = (duk_idx_t) DUK_VARARGS;
17545 }
17546 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17547 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
17548 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
17549 DUK_HOBJECT_FLAG_NEWENV |
17550 DUK_HOBJECT_FLAG_STRICT |
17551 DUK_HOBJECT_FLAG_NOTAIL |
17552 /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
17553 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
17554 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
17555
17556 lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
17557 if ((duk_idx_t) lf_len != nargs) {
17558 /* Explicit length is only needed if it differs from 'nargs'. */
17559 duk_push_int(ctx, (duk_int_t) lf_len);
17560 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
17561 }
17562 duk_push_lightfunc_name(ctx, tv);
17563 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
17564
17565 nf = duk_get_hnativefunction(ctx, -1);
17566 DUK_ASSERT(nf != NULL);
17567 nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
17568
17569 /* Enable DUKFUNC exotic behavior once properties are set up. */
17570 DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf);
17571 goto replace_value;
17572 }
17573#if defined(DUK_USE_FASTINT)
17574 case DUK_TAG_FASTINT:
17575#endif
17576 default: {
17577 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
17578 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17579 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17580 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
17581 proto = DUK_BIDX_NUMBER_PROTOTYPE;
17582 goto create_object;
17583 }
17584 }
17585 return;
17586
17587 create_object:
17588 (void) duk_push_object_helper(ctx, flags, proto);
17589
17590 /* Note: Boolean prototype's internal value property is not writable,
17591 * but duk_xdef_prop_stridx() disregards the write protection. Boolean
17592 * instances are immutable.
17593 *
17594 * String and buffer special behaviors are already enabled which is not
17595 * ideal, but a write to the internal value is not affected by them.
17596 */
17597 duk_dup(ctx, index);
17598 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
17599
17600 replace_value:
17601 duk_replace(ctx, index);
17602}
17603
17604/*
17605 * Type checking
17606 */
17607
17608DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t index, duk_small_uint_t tag) {
17609 duk_tval *tv;
17610
17611 tv = duk_get_tval(ctx, index);
17612 if (!tv) {
17613 return 0;
17614 }
17615 return (DUK_TVAL_GET_TAG(tv) == tag);
17616}
17617
17618DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t index, duk_uint_t flag_mask) {
17619 duk_hobject *obj;
17620
17621 DUK_ASSERT_CTX_VALID(ctx);
17622
17623 obj = duk_get_hobject(ctx, index);
17624 if (obj) {
17625 return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
17626 }
17627 return 0;
17628}
17629
17630DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
17631 duk_tval *tv;
17632
17633 DUK_ASSERT_CTX_VALID(ctx);
17634
17635 tv = duk_get_tval(ctx, index);
17636 if (!tv) {
17637 return DUK_TYPE_NONE;
17638 }
17639 switch (DUK_TVAL_GET_TAG(tv)) {
17640 case DUK_TAG_UNDEFINED:
17641 return DUK_TYPE_UNDEFINED;
17642 case DUK_TAG_NULL:
17643 return DUK_TYPE_NULL;
17644 case DUK_TAG_BOOLEAN:
17645 return DUK_TYPE_BOOLEAN;
17646 case DUK_TAG_STRING:
17647 return DUK_TYPE_STRING;
17648 case DUK_TAG_OBJECT:
17649 return DUK_TYPE_OBJECT;
17650 case DUK_TAG_BUFFER:
17651 return DUK_TYPE_BUFFER;
17652 case DUK_TAG_POINTER:
17653 return DUK_TYPE_POINTER;
17654 case DUK_TAG_LIGHTFUNC:
17655 return DUK_TYPE_LIGHTFUNC;
17656#if defined(DUK_USE_FASTINT)
17657 case DUK_TAG_FASTINT:
17658#endif
17659 default:
17660 /* Note: number has no explicit tag (in 8-byte representation) */
17661 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
17662 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17663 return DUK_TYPE_NUMBER;
17664 }
17665 DUK_UNREACHABLE();
17666}
17667
17668#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
17669DUK_LOCAL const char *duk__type_names[] = {
17670 "none",
17671 "undefined",
17672 "null",
17673 "boolean",
17674 "number",
17675 "string",
17676 "object",
17677 "buffer",
17678 "pointer",
17679 "lightfunc"
17680};
17681
17682DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) {
17683 duk_int_t type_tag;
17684
17685 type_tag = duk_get_type(ctx, index);
17686 DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
17687 DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
17688
17689 return duk__type_names[type_tag];
17690}
17691#endif
17692
17693DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) {
17694 DUK_ASSERT_CTX_VALID(ctx);
17695
17696 return (duk_get_type(ctx, index) == type) ? 1 : 0;
17697}
17698
17699DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) {
17700 duk_tval *tv;
17701
17702 DUK_ASSERT_CTX_VALID(ctx);
17703
17704 tv = duk_get_tval(ctx, index);
17705 if (!tv) {
17706 return DUK_TYPE_MASK_NONE;
17707 }
17708 switch (DUK_TVAL_GET_TAG(tv)) {
17709 case DUK_TAG_UNDEFINED:
17710 return DUK_TYPE_MASK_UNDEFINED;
17711 case DUK_TAG_NULL:
17712 return DUK_TYPE_MASK_NULL;
17713 case DUK_TAG_BOOLEAN:
17714 return DUK_TYPE_MASK_BOOLEAN;
17715 case DUK_TAG_STRING:
17716 return DUK_TYPE_MASK_STRING;
17717 case DUK_TAG_OBJECT:
17718 return DUK_TYPE_MASK_OBJECT;
17719 case DUK_TAG_BUFFER:
17720 return DUK_TYPE_MASK_BUFFER;
17721 case DUK_TAG_POINTER:
17722 return DUK_TYPE_MASK_POINTER;
17723 case DUK_TAG_LIGHTFUNC:
17724 return DUK_TYPE_MASK_LIGHTFUNC;
17725#if defined(DUK_USE_FASTINT)
17726 case DUK_TAG_FASTINT:
17727#endif
17728 default:
17729 /* Note: number has no explicit tag (in 8-byte representation) */
17730 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
17731 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17732 return DUK_TYPE_MASK_NUMBER;
17733 }
17734 DUK_UNREACHABLE();
17735}
17736
17737DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask) {
17738 duk_hthread *thr = (duk_hthread *) ctx;
17739
17740 DUK_ASSERT_CTX_VALID(ctx);
17741
17742 if (duk_get_type_mask(ctx, index) & mask) {
17743 return 1;
17744 }
17745 if (mask & DUK_TYPE_MASK_THROW) {
17746 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
17747 DUK_UNREACHABLE();
17748 }
17749 return 0;
17750}
17751
17752DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index) {
17753 DUK_ASSERT_CTX_VALID(ctx);
17754 return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED);
17755}
17756
17757DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index) {
17758 DUK_ASSERT_CTX_VALID(ctx);
17759 return duk__tag_check(ctx, index, DUK_TAG_NULL);
17760}
17761
17762DUK_EXTERNAL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index) {
17763 duk_tval *tv;
17764 duk_small_uint_t tag;
17765
17766 DUK_ASSERT_CTX_VALID(ctx);
17767
17768 tv = duk_get_tval(ctx, index);
17769 if (!tv) {
17770 return 0;
17771 }
17772 tag = DUK_TVAL_GET_TAG(tv);
17773 return (tag == DUK_TAG_UNDEFINED) || (tag == DUK_TAG_NULL);
17774}
17775
17776DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index) {
17777 DUK_ASSERT_CTX_VALID(ctx);
17778 return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN);
17779}
17780
17781DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) {
17782 duk_tval *tv;
17783
17784 DUK_ASSERT_CTX_VALID(ctx);
17785
17786 /*
17787 * Number is special because it doesn't have a specific
17788 * tag in the 8-byte representation.
17789 */
17790
17791 /* XXX: shorter version for 12-byte representation? */
17792
17793 tv = duk_get_tval(ctx, index);
17794 if (!tv) {
17795 return 0;
17796 }
17797 return DUK_TVAL_IS_NUMBER(tv);
17798}
17799
17800DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) {
17801 /* XXX: This will now return false for non-numbers, even though they would
17802 * coerce to NaN (as a general rule). In particular, duk_get_number()
17803 * returns a NaN for non-numbers, so should this function also return
17804 * true for non-numbers?
17805 */
17806
17807 duk_tval *tv;
17808
17809 DUK_ASSERT_CTX_VALID(ctx);
17810
17811 tv = duk_get_tval(ctx, index);
17812 if (!tv || !DUK_TVAL_IS_NUMBER(tv)) {
17813 return 0;
17814 }
17815 return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
17816}
17817
17818DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index) {
17819 DUK_ASSERT_CTX_VALID(ctx);
17820 return duk__tag_check(ctx, index, DUK_TAG_STRING);
17821}
17822
17823DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index) {
17824 DUK_ASSERT_CTX_VALID(ctx);
17825 return duk__tag_check(ctx, index, DUK_TAG_OBJECT);
17826}
17827
17828DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index) {
17829 DUK_ASSERT_CTX_VALID(ctx);
17830 return duk__tag_check(ctx, index, DUK_TAG_BUFFER);
17831}
17832
17833#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
17834DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
17835 duk_tval *tv;
17836
17837 DUK_ASSERT_CTX_VALID(ctx);
17838
17839 tv = duk_get_tval(ctx, idx);
17840 if (tv == NULL) {
17841 return 0;
17842 }
17843 if (DUK_TVAL_IS_BUFFER(tv)) {
17844 return 1;
17845 } else if (DUK_TVAL_IS_OBJECT(tv)) {
17846 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
17847 DUK_ASSERT(h != NULL);
17848 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
17849 return 1;
17850 }
17851 }
17852 return 0;
17853}
17854#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
17855DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
17856 DUK_ASSERT_CTX_VALID(ctx);
17857
17858 return duk_is_buffer(ctx, idx);
17859}
17860#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
17861
17862DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index) {
17863 DUK_ASSERT_CTX_VALID(ctx);
17864 return duk__tag_check(ctx, index, DUK_TAG_POINTER);
17865}
17866
17867DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index) {
17868 DUK_ASSERT_CTX_VALID(ctx);
17869 return duk__tag_check(ctx, index, DUK_TAG_LIGHTFUNC);
17870}
17871
17872DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index) {
17873 duk_hobject *obj;
17874
17875 DUK_ASSERT_CTX_VALID(ctx);
17876
17877 obj = duk_get_hobject(ctx, index);
17878 if (obj) {
17879 return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
17880 }
17881 return 0;
17882}
17883
17884DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index) {
17885 duk_tval *tv;
17886
17887 DUK_ASSERT_CTX_VALID(ctx);
17888
17889 tv = duk_get_tval(ctx, index);
17890 if (tv && DUK_TVAL_IS_LIGHTFUNC(tv)) {
17891 return 1;
17892 }
17893 return duk__obj_flag_any_default_false(ctx,
17894 index,
17895 DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
17896 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
17897 DUK_HOBJECT_FLAG_BOUND);
17898}
17899
17900DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index) {
17901 DUK_ASSERT_CTX_VALID(ctx);
17902 return duk__obj_flag_any_default_false(ctx,
17903 index,
17904 DUK_HOBJECT_FLAG_NATIVEFUNCTION);
17905}
17906
17907DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index) {
17908 DUK_ASSERT_CTX_VALID(ctx);
17909 return duk__obj_flag_any_default_false(ctx,
17910 index,
17911 DUK_HOBJECT_FLAG_COMPILEDFUNCTION);
17912}
17913
17914DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index) {
17915 DUK_ASSERT_CTX_VALID(ctx);
17916 return duk__obj_flag_any_default_false(ctx,
17917 index,
17918 DUK_HOBJECT_FLAG_BOUND);
17919}
17920
17921DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) {
17922 DUK_ASSERT_CTX_VALID(ctx);
17923 return duk__obj_flag_any_default_false(ctx,
17924 index,
17925 DUK_HOBJECT_FLAG_THREAD);
17926}
17927
17928DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
17929 duk_tval *tv;
17930
17931 DUK_ASSERT_CTX_VALID(ctx);
17932
17933 tv = duk_get_tval(ctx, index);
17934 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
17935 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17936 DUK_ASSERT(h != NULL);
17937 return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
17938 }
17939 return 0;
17940}
17941
17942DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) {
17943 duk_tval *tv;
17944
17945 DUK_ASSERT_CTX_VALID(ctx);
17946
17947 tv = duk_get_tval(ctx, index);
17948 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
17949 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17950 DUK_ASSERT(h != NULL);
17951 return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
17952 }
17953 return 0;
17954}
17955
17956DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index) {
17957 duk_tval *tv;
17958
17959 DUK_ASSERT_CTX_VALID(ctx);
17960
17961 tv = duk_get_tval(ctx, index);
17962 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
17963 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17964 DUK_ASSERT(h != NULL);
17965 return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
17966 }
17967 return 0;
17968}
17969
17970DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index) {
17971 duk_hthread *thr = (duk_hthread *) ctx;
17972 duk_hobject *h;
17973 duk_uint_t sanity;
17974
17975 DUK_ASSERT_CTX_VALID(ctx);
17976
17977 h = duk_get_hobject(ctx, index);
17978
17979 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
17980 do {
17981 if (!h) {
17982 return DUK_ERR_NONE;
17983 }
17984 if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
17985 return DUK_ERR_EVAL_ERROR;
17986 }
17987 if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) {
17988 return DUK_ERR_RANGE_ERROR;
17989 }
17990 if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) {
17991 return DUK_ERR_REFERENCE_ERROR;
17992 }
17993 if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) {
17994 return DUK_ERR_SYNTAX_ERROR;
17995 }
17996 if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) {
17997 return DUK_ERR_TYPE_ERROR;
17998 }
17999 if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) {
18000 return DUK_ERR_URI_ERROR;
18001 }
18002 if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) {
18003 return DUK_ERR_ERROR;
18004 }
18005
18006 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
18007 } while (--sanity > 0);
18008
18009 return DUK_ERR_NONE;
18010}
18011
18012/*
18013 * Pushers
18014 */
18015
18016DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) {
18017 duk_hthread *thr;
18018 duk_tval *tv_slot;
18019
18020 DUK_ASSERT_CTX_VALID(ctx);
18021 DUK_ASSERT(tv != NULL);
18022 thr = (duk_hthread *) ctx;
18023 DUK__CHECK_SPACE();
18024 tv_slot = thr->valstack_top++;
18025 DUK_TVAL_SET_TVAL(tv_slot, tv);
18026 DUK_TVAL_INCREF(thr, tv); /* no side effects */
18027}
18028
18029DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
18030 duk_hthread *thr;
18031
18032 DUK_ASSERT_CTX_VALID(ctx);
18033 thr = (duk_hthread *) ctx;
18034 DUK__CHECK_SPACE();
18035
18036 /* Because value stack init policy is 'undefined above top',
18037 * we don't need to write, just assert.
18038 */
18039 thr->valstack_top++;
18040 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
18041}
18042
18043DUK_EXTERNAL void duk_push_null(duk_context *ctx) {
18044 duk_hthread *thr;
18045 duk_tval *tv_slot;
18046
18047 DUK_ASSERT_CTX_VALID(ctx);
18048 thr = (duk_hthread *) ctx;
18049 DUK__CHECK_SPACE();
18050 tv_slot = thr->valstack_top++;
18051 DUK_TVAL_SET_NULL(tv_slot);
18052}
18053
18054DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) {
18055 duk_hthread *thr;
18056 duk_tval *tv_slot;
18057 duk_small_int_t b;
18058
18059 DUK_ASSERT_CTX_VALID(ctx);
18060 thr = (duk_hthread *) ctx;
18061 DUK__CHECK_SPACE();
18062 b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
18063 tv_slot = thr->valstack_top++;
18064 DUK_TVAL_SET_BOOLEAN(tv_slot, b);
18065}
18066
18067DUK_EXTERNAL void duk_push_true(duk_context *ctx) {
18068 duk_hthread *thr;
18069 duk_tval *tv_slot;
18070
18071 DUK_ASSERT_CTX_VALID(ctx);
18072 thr = (duk_hthread *) ctx;
18073 DUK__CHECK_SPACE();
18074 tv_slot = thr->valstack_top++;
18075 DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
18076}
18077
18078DUK_EXTERNAL void duk_push_false(duk_context *ctx) {
18079 duk_hthread *thr;
18080 duk_tval *tv_slot;
18081
18082 DUK_ASSERT_CTX_VALID(ctx);
18083 thr = (duk_hthread *) ctx;
18084 DUK__CHECK_SPACE();
18085 tv_slot = thr->valstack_top++;
18086 DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
18087}
18088
18089/* normalize NaN which may not match our canonical internal NaN */
18090DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
18091 duk_hthread *thr;
18092 duk_tval *tv_slot;
18093 duk_double_union du;
18094
18095 DUK_ASSERT_CTX_VALID(ctx);
18096 thr = (duk_hthread *) ctx;
18097 DUK__CHECK_SPACE();
18098 du.d = val;
18099 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
18100 tv_slot = thr->valstack_top++;
18101 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
18102}
18103
18104DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
18105#if defined(DUK_USE_FASTINT)
18106 duk_hthread *thr;
18107 duk_tval *tv_slot;
18108
18109 DUK_ASSERT_CTX_VALID(ctx);
18110 thr = (duk_hthread *) ctx;
18111 DUK__CHECK_SPACE();
18112 tv_slot = thr->valstack_top++;
18113#if DUK_INT_MAX <= 0x7fffffffL
18114 DUK_TVAL_SET_FASTINT_I32(tv_slot, (duk_int32_t) val);
18115#else
18116 if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
18117 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
18118 } else {
18119 duk_double_t = (duk_double_t) val;
18120 DUK_TVAL_SET_NUMBER(tv_slot, d);
18121 }
18122#endif
18123#else /* DUK_USE_FASTINT */
18124 duk_hthread *thr;
18125 duk_tval *tv_slot;
18126 duk_double_t d;
18127
18128 DUK_ASSERT_CTX_VALID(ctx);
18129 thr = (duk_hthread *) ctx;
18130 DUK__CHECK_SPACE();
18131 d = (duk_double_t) val;
18132 tv_slot = thr->valstack_top++;
18133 DUK_TVAL_SET_NUMBER(tv_slot, d);
18134#endif /* DUK_USE_FASTINT */
18135}
18136
18137DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
18138#if defined(DUK_USE_FASTINT)
18139 duk_hthread *thr;
18140 duk_tval *tv_slot;
18141
18142 DUK_ASSERT_CTX_VALID(ctx);
18143 thr = (duk_hthread *) ctx;
18144 DUK__CHECK_SPACE();
18145 tv_slot = thr->valstack_top++;
18146#if DUK_UINT_MAX <= 0xffffffffUL
18147 DUK_TVAL_SET_FASTINT_U32(tv_slot, (duk_uint32_t) val);
18148#else
18149 if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */
18150 /* XXX: take advantage of val being unsigned, no need to mask */
18151 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
18152 } else {
18153 duk_double_t = (duk_double_t) val;
18154 DUK_TVAL_SET_NUMBER(tv_slot, d);
18155 }
18156#endif
18157#else /* DUK_USE_FASTINT */
18158 duk_hthread *thr;
18159 duk_tval *tv_slot;
18160 duk_double_t d;
18161
18162 DUK_ASSERT_CTX_VALID(ctx);
18163 thr = (duk_hthread *) ctx;
18164 DUK__CHECK_SPACE();
18165 d = (duk_double_t) val;
18166 tv_slot = thr->valstack_top++;
18167 DUK_TVAL_SET_NUMBER(tv_slot, d);
18168#endif /* DUK_USE_FASTINT */
18169}
18170
18171DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
18172 duk_hthread *thr;
18173 duk_tval *tv_slot;
18174 duk_double_union du;
18175
18176 DUK_ASSERT_CTX_VALID(ctx);
18177 thr = (duk_hthread *) ctx;
18178 DUK__CHECK_SPACE();
18179 DUK_DBLUNION_SET_NAN(&du);
18180 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
18181 tv_slot = thr->valstack_top++;
18182 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
18183}
18184
18185DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) {
18186 duk_hthread *thr = (duk_hthread *) ctx;
18187 duk_hstring *h;
18188 duk_tval *tv_slot;
18189
18190 DUK_ASSERT_CTX_VALID(ctx);
18191
18192 /* check stack before interning (avoid hanging temp) */
18193 if (thr->valstack_top >= thr->valstack_end) {
18194 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
18195 }
18196
18197 /* NULL with zero length represents an empty string; NULL with higher
18198 * length is also now trated like an empty string although it is
18199 * a bit dubious. This is unlike duk_push_string() which pushes a
18200 * 'null' if the input string is a NULL.
18201 */
18202 if (!str) {
18203 len = 0;
18204 }
18205
18206 /* Check for maximum string length */
18207 if (len > DUK_HSTRING_MAX_BYTELEN) {
18208 DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
18209 }
18210
18211 h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
18212 DUK_ASSERT(h != NULL);
18213
18214 tv_slot = thr->valstack_top++;
18215 DUK_TVAL_SET_STRING(tv_slot, h);
18216 DUK_HSTRING_INCREF(thr, h); /* no side effects */
18217
18218 return (const char *) DUK_HSTRING_GET_DATA(h);
18219}
18220
18221DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) {
18222 DUK_ASSERT_CTX_VALID(ctx);
18223
18224 if (str) {
18225 return duk_push_lstring(ctx, str, DUK_STRLEN(str));
18226 } else {
18227 duk_push_null(ctx);
18228 return NULL;
18229 }
18230}
18231
18232#ifdef DUK_USE_FILE_IO
18233/* This is a bit clunky because it is ANSI C portable. Should perhaps
18234 * relocate to another file because this is potentially platform
18235 * dependent.
18236 */
18237DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
18238 duk_hthread *thr = (duk_hthread *) ctx;
18239 duk_file *f = NULL;
18240 char *buf;
18241 long sz; /* ANSI C typing */
18242
18243 DUK_ASSERT_CTX_VALID(ctx);
18244
18245 if (!path) {
18246 goto fail;
18247 }
18248 f = DUK_FOPEN(path, "rb");
18249 if (!f) {
18250 goto fail;
18251 }
18252 if (DUK_FSEEK(f, 0, SEEK_END) < 0) {
18253 goto fail;
18254 }
18255 sz = DUK_FTELL(f);
18256 if (sz < 0) {
18257 goto fail;
18258 }
18259 if (DUK_FSEEK(f, 0, SEEK_SET) < 0) {
18260 goto fail;
18261 }
18262 buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz);
18263 DUK_ASSERT(buf != NULL);
18264 if ((duk_size_t) DUK_FREAD(buf, 1, (size_t) sz, f) != (duk_size_t) sz) {
18265 goto fail;
18266 }
18267 (void) DUK_FCLOSE(f); /* ignore fclose() error */
18268 f = NULL;
18269 return duk_to_string(ctx, -1);
18270
18271 fail:
18272 if (f) {
18273 DUK_FCLOSE(f);
18274 }
18275
18276 if (flags != 0) {
18277 DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
18278 duk_push_undefined(ctx);
18279 } else {
18280 /* XXX: string not shared because it is conditional */
18281 DUK_ERROR_TYPE(thr, "read file error");
18282 }
18283 return NULL;
18284}
18285#else
18286DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
18287 duk_hthread *thr = (duk_hthread *) ctx;
18288 DUK_ASSERT_CTX_VALID(ctx);
18289 DUK_UNREF(path);
18290
18291 if (flags != 0) {
18292 DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
18293 duk_push_undefined(ctx);
18294 } else {
18295 /* XXX: string not shared because it is conditional */
18296 DUK_ERROR_UNSUPPORTED(thr, "file I/O disabled");
18297 }
18298 return NULL;
18299}
18300#endif /* DUK_USE_FILE_IO */
18301
18302DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) {
18303 duk_hthread *thr;
18304 duk_tval *tv_slot;
18305
18306 DUK_ASSERT_CTX_VALID(ctx);
18307 thr = (duk_hthread *) ctx;
18308 DUK__CHECK_SPACE();
18309 tv_slot = thr->valstack_top++;
18310 DUK_TVAL_SET_POINTER(tv_slot, val);
18311}
18312
18313DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) {
18314 duk_hthread *thr;
18315 duk_tval *tv_slot;
18316
18317 DUK_ASSERT_CTX_VALID(ctx);
18318 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
18319 thr = (duk_hthread *) ctx;
18320 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
18321 DUK__CHECK_SPACE();
18322
18323 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
18324 tv_slot = thr->valstack_top++;
18325
18326 if (DUK_UNLIKELY(thr->callstack_top == 0)) {
18327 if (check_object_coercible) {
18328 goto type_error;
18329 }
18330 /* 'undefined' already on stack top */
18331 } else {
18332 duk_tval *tv;
18333
18334 /* 'this' binding is just before current activation's bottom */
18335 DUK_ASSERT(thr->valstack_bottom > thr->valstack);
18336 tv = thr->valstack_bottom - 1;
18337 if (check_object_coercible &&
18338 (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) {
18339 /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */
18340 goto type_error;
18341 }
18342
18343 DUK_TVAL_SET_TVAL(tv_slot, tv);
18344 DUK_TVAL_INCREF(thr, tv);
18345 }
18346 return;
18347
18348 type_error:
18349 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
18350}
18351
18352DUK_EXTERNAL void duk_push_this(duk_context *ctx) {
18353 DUK_ASSERT_CTX_VALID(ctx);
18354
18355 duk__push_this_helper(ctx, 0 /*check_object_coercible*/);
18356}
18357
18358DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) {
18359 DUK_ASSERT_CTX_VALID(ctx);
18360
18361 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
18362}
18363
18364DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
18365 duk_hobject *h;
18366
18367 DUK_ASSERT_CTX_VALID(ctx);
18368
18369 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
18370 duk_to_object(ctx, -1);
18371 h = duk_get_hobject(ctx, -1);
18372 DUK_ASSERT(h != NULL);
18373 return h;
18374}
18375
18376DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
18377 duk_hstring *h;
18378
18379 DUK_ASSERT_CTX_VALID(ctx);
18380
18381 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
18382 duk_to_string(ctx, -1);
18383 h = duk_get_hstring(ctx, -1);
18384 DUK_ASSERT(h != NULL);
18385 return h;
18386}
18387
18388DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) {
18389 duk_hthread *thr;
18390
18391 DUK_ASSERT(ctx != NULL);
18392 thr = (duk_hthread *) ctx;
18393
18394 DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
18395 DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
18396 DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
18397
18398 return thr->valstack_bottom - 1;
18399}
18400
18401DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) {
18402 duk_hthread *thr = (duk_hthread *) ctx;
18403 duk_activation *act;
18404
18405 DUK_ASSERT_CTX_VALID(ctx);
18406 DUK_ASSERT(thr != NULL);
18407 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
18408 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
18409
18410 act = duk_hthread_get_current_activation(thr);
18411 if (act) {
18412 duk_push_tval(ctx, &act->tv_func);
18413 } else {
18414 duk_push_undefined(ctx);
18415 }
18416}
18417
18418DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) {
18419 duk_hthread *thr = (duk_hthread *) ctx;
18420
18421 DUK_ASSERT_CTX_VALID(ctx);
18422 DUK_ASSERT(thr != NULL);
18423
18424 if (thr->heap->curr_thread) {
18425 duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
18426 } else {
18427 duk_push_undefined(ctx);
18428 }
18429}
18430
18431DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) {
18432 DUK_ASSERT_CTX_VALID(ctx);
18433
18434 duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
18435}
18436
18437/* XXX: size optimize */
18438DUK_LOCAL void duk__push_stash(duk_context *ctx) {
18439 DUK_ASSERT_CTX_VALID(ctx);
18440 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) {
18441 DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
18442 duk_pop(ctx);
18443 duk_push_object_internal(ctx);
18444 duk_dup_top(ctx);
18445 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
18446 }
18447 duk_remove(ctx, -2);
18448}
18449
18450DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) {
18451 duk_hthread *thr = (duk_hthread *) ctx;
18452 duk_heap *heap;
18453 DUK_ASSERT_CTX_VALID(ctx);
18454 heap = thr->heap;
18455 DUK_ASSERT(heap->heap_object != NULL);
18456 duk_push_hobject(ctx, heap->heap_object);
18457 duk__push_stash(ctx);
18458}
18459
18460DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) {
18461 DUK_ASSERT_CTX_VALID(ctx);
18462 duk_push_global_object(ctx);
18463 duk__push_stash(ctx);
18464}
18465
18466DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
18467 duk_hthread *thr = (duk_hthread *) ctx;
18468 DUK_ASSERT_CTX_VALID(ctx);
18469 if (!target_ctx) {
18470 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
18471 return; /* not reached */
18472 }
18473 duk_push_hobject(ctx, (duk_hobject *) target_ctx);
18474 duk__push_stash(ctx);
18475}
18476
18477/* XXX: duk_ssize_t would be useful here */
18478DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
18479 duk_int_t len;
18480
18481 DUK_ASSERT_CTX_VALID(ctx);
18482 DUK_UNREF(ctx);
18483
18484 /* NUL terminator handling doesn't matter here */
18485 len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
18486 if (len < (duk_int_t) sz) {
18487 /* Return value of 'sz' or more indicates output was (potentially)
18488 * truncated.
18489 */
18490 return (duk_int_t) len;
18491 }
18492 return -1;
18493}
18494
18495DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
18496 duk_hthread *thr = (duk_hthread *) ctx;
18497 duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
18498 duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
18499 duk_bool_t pushed_buf = 0;
18500 void *buf;
18501 duk_int_t len; /* XXX: duk_ssize_t */
18502 const char *res;
18503
18504 DUK_ASSERT_CTX_VALID(ctx);
18505
18506 /* special handling of fmt==NULL */
18507 if (!fmt) {
18508 duk_hstring *h_str;
18509 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
18510 h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); /* rely on interning, must be this string */
18511 return (const char *) DUK_HSTRING_GET_DATA(h_str);
18512 }
18513
18514 /* initial estimate based on format string */
18515 sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */
18516 if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) {
18517 sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
18518 }
18519 DUK_ASSERT(sz > 0);
18520
18521 /* Try to make do with a stack buffer to avoid allocating a temporary buffer.
18522 * This works 99% of the time which is quite nice.
18523 */
18524 for (;;) {
18525 va_list ap_copy; /* copied so that 'ap' can be reused */
18526
18527 if (sz <= sizeof(stack_buf)) {
18528 buf = stack_buf;
18529 } else if (!pushed_buf) {
18530 pushed_buf = 1;
18531 buf = duk_push_dynamic_buffer(ctx, sz);
18532 } else {
18533 buf = duk_resize_buffer(ctx, -1, sz);
18534 }
18535 DUK_ASSERT(buf != NULL);
18536
18537 DUK_VA_COPY(ap_copy, ap);
18538 len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy);
18539 va_end(ap_copy);
18540 if (len >= 0) {
18541 break;
18542 }
18543
18544 /* failed, resize and try again */
18545 sz = sz * 2;
18546 if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
18547 DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG);
18548 }
18549 }
18550
18551 /* Cannot use duk_to_string() on the buffer because it is usually
18552 * larger than 'len'. Also, 'buf' is usually a stack buffer.
18553 */
18554 res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
18555 if (pushed_buf) {
18556 duk_remove(ctx, -2);
18557 }
18558 return res;
18559}
18560
18561DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
18562 va_list ap;
18563 const char *ret;
18564
18565 DUK_ASSERT_CTX_VALID(ctx);
18566
18567 /* allow fmt==NULL */
18568 va_start(ap, fmt);
18569 ret = duk_push_vsprintf(ctx, fmt, ap);
18570 va_end(ap);
18571
18572 return ret;
18573}
18574
18575DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
18576 duk_hthread *thr = (duk_hthread *) ctx;
18577 duk_tval *tv_slot;
18578 duk_hobject *h;
18579 duk_idx_t ret;
18580
18581 DUK_ASSERT_CTX_VALID(ctx);
18582 DUK_ASSERT(prototype_bidx == -1 ||
18583 (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
18584
18585 /* check stack first */
18586 if (thr->valstack_top >= thr->valstack_end) {
18587 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
18588 }
18589
18590 h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
18591 if (!h) {
18592 DUK_ERROR_ALLOC_DEFMSG(thr);
18593 }
18594
18595 DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
18596
18597 tv_slot = thr->valstack_top;
18598 DUK_TVAL_SET_OBJECT(tv_slot, h);
18599 DUK_HOBJECT_INCREF(thr, h); /* no side effects */
18600 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18601 thr->valstack_top++;
18602
18603 /* object is now reachable */
18604
18605 if (prototype_bidx >= 0) {
18606 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
18607 } else {
18608 DUK_ASSERT(prototype_bidx == -1);
18609 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
18610 }
18611
18612 return ret;
18613}
18614
18615DUK_INTERNAL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
18616 duk_hthread *thr = (duk_hthread *) ctx;
18617 duk_idx_t ret;
18618 duk_hobject *h;
18619
18620 DUK_ASSERT_CTX_VALID(ctx);
18621
18622 ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
18623 h = duk_get_hobject(ctx, -1);
18624 DUK_ASSERT(h != NULL);
18625 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
18626 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
18627 return ret;
18628}
18629
18630DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) {
18631 DUK_ASSERT_CTX_VALID(ctx);
18632
18633 return duk_push_object_helper(ctx,
18634 DUK_HOBJECT_FLAG_EXTENSIBLE |
18635 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
18636 DUK_BIDX_OBJECT_PROTOTYPE);
18637}
18638
18639DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
18640 duk_hthread *thr = (duk_hthread *) ctx;
18641 duk_hobject *obj;
18642 duk_idx_t ret;
18643
18644 DUK_ASSERT_CTX_VALID(ctx);
18645
18646 ret = duk_push_object_helper(ctx,
18647 DUK_HOBJECT_FLAG_EXTENSIBLE |
18648 DUK_HOBJECT_FLAG_ARRAY_PART |
18649 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY),
18650 DUK_BIDX_ARRAY_PROTOTYPE);
18651
18652 obj = duk_require_hobject(ctx, ret);
18653
18654 /*
18655 * An array must have a 'length' property (E5 Section 15.4.5.2).
18656 * The special array behavior flag must only be enabled once the
18657 * length property has been added.
18658 *
18659 * The internal property must be a number (and preferably a
18660 * fastint if fastint support is enabled).
18661 */
18662
18663 duk_push_int(ctx, 0);
18664#if defined(DUK_USE_FASTINT)
18665 DUK_ASSERT(DUK_TVAL_IS_FASTINT(duk_require_tval(ctx, -1)));
18666#endif
18667
18668 duk_hobject_define_property_internal(thr,
18669 obj,
18670 DUK_HTHREAD_STRING_LENGTH(thr),
18671 DUK_PROPDESC_FLAGS_W);
18672 DUK_HOBJECT_SET_EXOTIC_ARRAY(obj);
18673
18674 return ret;
18675}
18676
18677DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
18678 duk_hthread *thr = (duk_hthread *) ctx;
18679 duk_hthread *obj;
18680 duk_idx_t ret;
18681 duk_tval *tv_slot;
18682
18683 DUK_ASSERT_CTX_VALID(ctx);
18684
18685 /* check stack first */
18686 if (thr->valstack_top >= thr->valstack_end) {
18687 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
18688 }
18689
18690 obj = duk_hthread_alloc(thr->heap,
18691 DUK_HOBJECT_FLAG_EXTENSIBLE |
18692 DUK_HOBJECT_FLAG_THREAD |
18693 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
18694 if (!obj) {
18695 DUK_ERROR_ALLOC_DEFMSG(thr);
18696 }
18697 obj->state = DUK_HTHREAD_STATE_INACTIVE;
18698#if defined(DUK_USE_ROM_STRINGS)
18699 /* Nothing to initialize, strs[] is in ROM. */
18700#else
18701#if defined(DUK_USE_HEAPPTR16)
18702 obj->strs16 = thr->strs16;
18703#else
18704 obj->strs = thr->strs;
18705#endif
18706#endif
18707 DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
18708
18709 /* make the new thread reachable */
18710 tv_slot = thr->valstack_top;
18711 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18712 DUK_HTHREAD_INCREF(thr, obj);
18713 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18714 thr->valstack_top++;
18715
18716 /* important to do this *after* pushing, to make the thread reachable for gc */
18717 if (!duk_hthread_init_stacks(thr->heap, obj)) {
18718 DUK_ERROR_ALLOC_DEFMSG(thr);
18719 }
18720
18721 /* initialize built-ins - either by copying or creating new ones */
18722 if (flags & DUK_THREAD_NEW_GLOBAL_ENV) {
18723 duk_hthread_create_builtin_objects(obj);
18724 } else {
18725 duk_hthread_copy_builtin_objects(thr, obj);
18726 }
18727
18728 /* default prototype (Note: 'obj' must be reachable) */
18729 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
18730
18731 /* Initial stack size satisfies the stack spare constraints so there
18732 * is no need to require stack here.
18733 */
18734 DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
18735 DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
18736
18737 return ret;
18738}
18739
18740DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
18741 duk_hthread *thr = (duk_hthread *) ctx;
18742 duk_hcompiledfunction *obj;
18743 duk_idx_t ret;
18744 duk_tval *tv_slot;
18745
18746 DUK_ASSERT_CTX_VALID(ctx);
18747
18748 /* check stack first */
18749 if (thr->valstack_top >= thr->valstack_end) {
18750 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
18751 }
18752
18753 /* Template functions are not strictly constructable (they don't
18754 * have a "prototype" property for instance), so leave the
18755 * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
18756 */
18757
18758 obj = duk_hcompiledfunction_alloc(thr->heap,
18759 DUK_HOBJECT_FLAG_EXTENSIBLE |
18760 DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
18761 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
18762 if (!obj) {
18763 DUK_ERROR_ALLOC_DEFMSG(thr);
18764 }
18765
18766 DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
18767
18768 tv_slot = thr->valstack_top;
18769 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18770 DUK_HOBJECT_INCREF(thr, obj);
18771 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18772 thr->valstack_top++;
18773
18774 /* default prototype (Note: 'obj' must be reachable) */
18775 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
18776
18777 return ret;
18778}
18779
18780DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) {
18781 duk_hthread *thr = (duk_hthread *) ctx;
18782 duk_hnativefunction *obj;
18783 duk_idx_t ret;
18784 duk_tval *tv_slot;
18785 duk_int16_t func_nargs;
18786
18787 DUK_ASSERT_CTX_VALID(ctx);
18788
18789 /* check stack first */
18790 if (thr->valstack_top >= thr->valstack_end) {
18791 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
18792 }
18793 if (func == NULL) {
18794 goto api_error;
18795 }
18796 if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
18797 func_nargs = (duk_int16_t) nargs;
18798 } else if (nargs == DUK_VARARGS) {
18799 func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
18800 } else {
18801 goto api_error;
18802 }
18803
18804 obj = duk_hnativefunction_alloc(thr->heap, flags);
18805 if (!obj) {
18806 DUK_ERROR_ALLOC_DEFMSG(thr);
18807 }
18808
18809 obj->func = func;
18810 obj->nargs = func_nargs;
18811
18812 DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld",
18813 (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs));
18814
18815 tv_slot = thr->valstack_top;
18816 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18817 DUK_HOBJECT_INCREF(thr, obj);
18818 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18819 thr->valstack_top++;
18820
18821 /* default prototype (Note: 'obj' must be reachable) */
18822 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
18823
18824 return ret;
18825
18826 api_error:
18827 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
18828 return 0; /* not reached */
18829}
18830
18831DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
18832 duk_uint_t flags;
18833
18834 DUK_ASSERT_CTX_VALID(ctx);
18835
18836 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
18837 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
18838 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
18839 DUK_HOBJECT_FLAG_NEWENV |
18840 DUK_HOBJECT_FLAG_STRICT |
18841 DUK_HOBJECT_FLAG_NOTAIL |
18842 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
18843 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
18844
18845 return duk__push_c_function_raw(ctx, func, nargs, flags);
18846}
18847
18848DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
18849 duk_uint_t flags;
18850
18851 DUK_ASSERT_CTX_VALID(ctx);
18852
18853 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
18854 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
18855 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
18856 DUK_HOBJECT_FLAG_NEWENV |
18857 DUK_HOBJECT_FLAG_STRICT |
18858 DUK_HOBJECT_FLAG_NOTAIL |
18859 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
18860
18861 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
18862}
18863
18864DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
18865 duk_uint_t flags;
18866
18867 DUK_ASSERT_CTX_VALID(ctx);
18868
18869 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
18870 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
18871 DUK_HOBJECT_FLAG_NEWENV |
18872 DUK_HOBJECT_FLAG_STRICT |
18873 DUK_HOBJECT_FLAG_NOTAIL |
18874 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
18875
18876 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
18877}
18878
18879DUK_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) {
18880 duk_hthread *thr = (duk_hthread *) ctx;
18881 duk_tval tv_tmp;
18882 duk_small_uint_t lf_flags;
18883
18884 DUK_ASSERT_CTX_VALID(ctx);
18885
18886 /* check stack first */
18887 if (thr->valstack_top >= thr->valstack_end) {
18888 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
18889 }
18890
18891 if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
18892 /* as is */
18893 } else if (nargs == DUK_VARARGS) {
18894 nargs = DUK_LFUNC_NARGS_VARARGS;
18895 } else {
18896 goto api_error;
18897 }
18898 if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) {
18899 goto api_error;
18900 }
18901 if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) {
18902 goto api_error;
18903 }
18904
18905 lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs);
18906 DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags);
18907 duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */
18908 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
18909 return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
18910
18911 api_error:
18912 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
18913 return 0; /* not reached */
18914}
18915
18916DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
18917 duk_hthread *thr = (duk_hthread *) ctx;
18918 duk_hbufferobject *obj;
18919 duk_tval *tv_slot;
18920
18921 DUK_ASSERT(ctx != NULL);
18922 DUK_ASSERT(prototype_bidx >= 0);
18923
18924 /* check stack first */
18925 if (thr->valstack_top >= thr->valstack_end) {
18926 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
18927 }
18928
18929 obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class);
18930 if (!obj) {
18931 DUK_ERROR_ALLOC_DEFMSG(thr);
18932 }
18933
18934 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
18935 DUK_ASSERT_HBUFFEROBJECT_VALID(obj);
18936
18937 tv_slot = thr->valstack_top;
18938 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18939 DUK_HOBJECT_INCREF(thr, obj);
18940 thr->valstack_top++;
18941
18942 return obj;
18943}
18944
18945/* XXX: There's quite a bit of overlap with buffer creation handling in
18946 * duk_bi_buffer.c. Look for overlap and refactor.
18947 */
18948#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,isview) \
18949 (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (isview))
18950
18951#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
18952static const duk_uint32_t duk__bufobj_flags_lookup[] = {
18953 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DUKTAPE_BUFFER */
18954 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_NODEJS_BUFFER */
18955 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
18956 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_DATAVIEW */
18957 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
18958 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
18959 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
18960 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
18961 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
18962 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
18963 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
18964 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
18965 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
18966};
18967#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
18968/* Only allow Duktape.Buffer when support disabled. */
18969static const duk_uint32_t duk__bufobj_flags_lookup[] = {
18970 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0) /* DUK_BUFOBJ_DUKTAPE_BUFFER */
18971};
18972#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
18973#undef DUK__PACK_ARGS
18974
18975DUK_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) {
18976 duk_hthread *thr;
18977 duk_hbufferobject *h_bufobj;
18978 duk_hbuffer *h_val;
18979 duk_uint32_t tmp;
18980 duk_uint_t classnum;
18981 duk_uint_t protobidx;
18982 duk_uint_t lookupidx;
18983 duk_uint_t uint_offset, uint_length, uint_added;
18984
18985 DUK_ASSERT_CTX_VALID(ctx);
18986 thr = (duk_hthread *) ctx;
18987 DUK_UNREF(thr);
18988
18989 /* The underlying types for offset/length in duk_hbufferobject is
18990 * duk_uint_t; make sure argument values fit and that offset + length
18991 * does not wrap.
18992 */
18993 uint_offset = (duk_uint_t) byte_offset;
18994 uint_length = (duk_uint_t) byte_length;
18995 if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
18996 if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) {
18997 goto range_error;
18998 }
18999 }
19000 uint_added = uint_offset + uint_length;
19001 if (uint_added < uint_offset) {
19002 goto range_error;
19003 }
19004 DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
19005
19006 DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
19007 lookupidx = flags & 0x0f; /* 4 low bits */
19008 if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) {
19009 goto arg_error;
19010 }
19011 tmp = duk__bufobj_flags_lookup[lookupidx];
19012 classnum = tmp >> 24;
19013 protobidx = (tmp >> 16) & 0xff;
19014
19015 h_val = duk_require_hbuffer(ctx, idx_buffer);
19016 DUK_ASSERT(h_val != NULL);
19017
19018 h_bufobj = duk_push_bufferobject_raw(ctx,
19019 DUK_HOBJECT_FLAG_EXTENSIBLE |
19020 DUK_HOBJECT_FLAG_BUFFEROBJECT |
19021 DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
19022 protobidx);
19023 DUK_ASSERT(h_bufobj != NULL);
19024
19025 h_bufobj->buf = h_val;
19026 DUK_HBUFFER_INCREF(thr, h_val);
19027 h_bufobj->offset = uint_offset;
19028 h_bufobj->length = uint_length;
19029 h_bufobj->shift = (tmp >> 4) & 0x0f;
19030 h_bufobj->elem_type = (tmp >> 8) & 0xff;
19031 h_bufobj->is_view = tmp & 0x0f;
19032 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
19033
19034#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
19035 /* TypedArray views need an automatic ArrayBuffer which must be
19036 * provided as .buffer property of the view. Just create a new
19037 * ArrayBuffer sharing the same underlying buffer.
19038 *
19039 * The ArrayBuffer offset is always set to zero, so that if one
19040 * accesses the ArrayBuffer at the view's .byteOffset, the value
19041 * matches the view at index 0.
19042 */
19043 if (flags & DUK_BUFOBJ_CREATE_ARRBUF) {
19044 h_bufobj = duk_push_bufferobject_raw(ctx,
19045 DUK_HOBJECT_FLAG_EXTENSIBLE |
19046 DUK_HOBJECT_FLAG_BUFFEROBJECT |
19047 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
19048 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
19049
19050 DUK_ASSERT(h_bufobj != NULL);
19051
19052 h_bufobj->buf = h_val;
19053 DUK_HBUFFER_INCREF(thr, h_val);
19054 h_bufobj->offset = 0;
19055 h_bufobj->length = uint_offset + uint_length; /* Wrap checked above. */
19056 DUK_ASSERT(h_bufobj->shift == 0);
19057 h_bufobj->elem_type = DUK_HBUFFEROBJECT_ELEM_UINT8;
19058 DUK_ASSERT(h_bufobj->is_view == 0);
19059 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
19060
19061 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
19062 duk_compact(ctx, -1);
19063 }
19064#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
19065
19066 return;
19067
19068 range_error:
19069 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
19070 return; /* not reached */
19071
19072 arg_error:
19073 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CALL_ARGS);
19074 return; /* not reached */
19075}
19076
19077DUK_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) {
19078 duk_hthread *thr = (duk_hthread *) ctx;
19079 duk_idx_t ret;
19080 duk_hobject *proto;
19081#ifdef DUK_USE_AUGMENT_ERROR_CREATE
19082 duk_bool_t noblame_fileline;
19083#endif
19084
19085 DUK_ASSERT_CTX_VALID(ctx);
19086 DUK_ASSERT(thr != NULL);
19087 DUK_UNREF(filename);
19088 DUK_UNREF(line);
19089
19090 /* Error code also packs a tracedata related flag. */
19091#ifdef DUK_USE_AUGMENT_ERROR_CREATE
19092 noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
19093#endif
19094 err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
19095
19096 /* error gets its 'name' from the prototype */
19097 proto = duk_error_prototype_from_code(thr, err_code);
19098 ret = duk_push_object_helper_proto(ctx,
19099 DUK_HOBJECT_FLAG_EXTENSIBLE |
19100 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
19101 proto);
19102
19103 /* ... and its 'message' from an instance property */
19104 if (fmt) {
19105 duk_push_vsprintf(ctx, fmt, ap);
19106 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
19107 } else {
19108 /* If no explicit message given, put error code into message field
19109 * (as a number). This is not fully in keeping with the Ecmascript
19110 * error model because messages are supposed to be strings (Error
19111 * constructors use ToString() on their argument). However, it's
19112 * probably more useful than having a separate 'code' property.
19113 */
19114 duk_push_int(ctx, err_code);
19115 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
19116 }
19117
19118 /* XXX: .code = err_code disabled, not sure if useful */
19119
19120 /* Creation time error augmentation */
19121#ifdef DUK_USE_AUGMENT_ERROR_CREATE
19122 /* filename may be NULL in which case file/line is not recorded */
19123 duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */
19124#endif
19125
19126 return ret;
19127}
19128
19129DUK_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, ...) {
19130 va_list ap;
19131 duk_idx_t ret;
19132
19133 DUK_ASSERT_CTX_VALID(ctx);
19134
19135 va_start(ap, fmt);
19136 ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19137 va_end(ap);
19138 return ret;
19139}
19140
19141#if !defined(DUK_USE_VARIADIC_MACROS)
19142DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
19143 const char *filename = duk_api_global_filename;
19144 duk_int_t line = duk_api_global_line;
19145 va_list ap;
19146 duk_idx_t ret;
19147
19148 DUK_ASSERT_CTX_VALID(ctx);
19149
19150 duk_api_global_filename = NULL;
19151 duk_api_global_line = 0;
19152 va_start(ap, fmt);
19153 ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19154 va_end(ap);
19155 return ret;
19156}
19157#endif /* DUK_USE_VARIADIC_MACROS */
19158
19159DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) {
19160 duk_hthread *thr = (duk_hthread *) ctx;
19161 duk_tval *tv_slot;
19162 duk_hbuffer *h;
19163 void *buf_data;
19164
19165 DUK_ASSERT_CTX_VALID(ctx);
19166
19167 /* check stack first */
19168 if (thr->valstack_top >= thr->valstack_end) {
19169 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
19170 }
19171
19172 /* Check for maximum buffer length. */
19173 if (size > DUK_HBUFFER_MAX_BYTELEN) {
19174 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
19175 }
19176
19177 h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
19178 if (!h) {
19179 DUK_ERROR_ALLOC_DEFMSG(thr);
19180 }
19181
19182 tv_slot = thr->valstack_top;
19183 DUK_TVAL_SET_BUFFER(tv_slot, h);
19184 DUK_HBUFFER_INCREF(thr, h);
19185 thr->valstack_top++;
19186
19187 return (void *) buf_data;
19188}
19189
19190#if defined(DUK_USE_ASSERTIONS)
19191DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) {
19192 duk_heaphdr *h;
19193 duk_heaphdr *curr;
19194 duk_hthread *thr;
19195 duk_bool_t found = 0;
19196
19197 thr = (duk_hthread *) ctx;
19198 h = (duk_heaphdr *) ptr;
19199 if (h == NULL) {
19200 /* Allowed. */
19201 return;
19202 }
19203 DUK_ASSERT(h != NULL);
19204 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
19205
19206 /* One particular problem case is where an object has been
19207 * queued for finalization but the finalizer hasn't yet been
19208 * executed.
19209 *
19210 * Corner case: we're running in a finalizer for object X, and
19211 * user code calls duk_push_heapptr() for X itself. In this
19212 * case X will be in finalize_list, and we can detect the case
19213 * by seeing that X's FINALIZED flag is set (which is done before
19214 * the finalizer starts executing).
19215 */
19216 for (curr = thr->heap->finalize_list;
19217 curr != NULL;
19218 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
19219 if (curr == h) {
19220 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
19221 /* Object is currently being finalized. */
19222 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
19223 found = 1;
19224 } else {
19225 DUK_ASSERT(0);
19226 }
19227 }
19228 }
19229
19230 /* Also check for the refzero_list; must not be there unless it is
19231 * being finalized when duk_push_heapptr() is called.
19232 *
19233 * Corner case: similar to finalize_list.
19234 */
19235#if defined(DUK_USE_REFERENCE_COUNTING)
19236 for (curr = thr->heap->refzero_list;
19237 curr != NULL;
19238 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
19239 if (curr == h) {
19240 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
19241 /* Object is currently being finalized. */
19242 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
19243 found = 1;
19244 } else {
19245 DUK_ASSERT(0);
19246 }
19247 }
19248 }
19249#endif
19250
19251 /* If not present in finalize_list or refzero_list, the pointer
19252 * must be either in heap_allocated or the string table.
19253 */
19254 if (DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_STRING) {
19255 /* String table assert check omitted from 1.x branch
19256 * backport.
19257 */
19258 } else {
19259 for (curr = thr->heap->heap_allocated;
19260 curr != NULL;
19261 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
19262 if (curr == h) {
19263 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
19264 found = 1;
19265 }
19266 }
19267 DUK_ASSERT(found != 0);
19268 }
19269}
19270#endif /* DUK_USE_ASSERTIONS */
19271
19272DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
19273 duk_hthread *thr = (duk_hthread *) ctx;
19274 duk_idx_t ret;
19275
19276 DUK_ASSERT_CTX_VALID(ctx);
19277
19278 /* Reviving an object using a heap pointer is a dangerous API
19279 * operation: if the application doesn't guarantee that the
19280 * pointer target is always reachable, difficult-to-diagnose
19281 * problems may ensue. Try to validate the 'ptr' argument to
19282 * the extent possible.
19283 */
19284
19285#if defined(DUK_USE_ASSERTIONS)
19286 duk__validate_push_heapptr(ctx, ptr);
19287#endif
19288
19289 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
19290
19291 if (ptr == NULL) {
19292 goto push_undefined;
19293 }
19294
19295 switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
19296 case DUK_HTYPE_STRING:
19297 duk_push_hstring(ctx, (duk_hstring *) ptr);
19298 break;
19299 case DUK_HTYPE_OBJECT:
19300 duk_push_hobject(ctx, (duk_hobject *) ptr);
19301 break;
19302 case DUK_HTYPE_BUFFER:
19303 duk_push_hbuffer(ctx, (duk_hbuffer *) ptr);
19304 break;
19305 default:
19306 goto push_undefined;
19307 }
19308 return ret;
19309
19310 push_undefined:
19311 duk_push_undefined(ctx);
19312 return ret;
19313}
19314
19315DUK_INTERNAL duk_idx_t duk_push_object_internal(duk_context *ctx) {
19316 return duk_push_object_helper(ctx,
19317 DUK_HOBJECT_FLAG_EXTENSIBLE |
19318 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
19319 -1); /* no prototype */
19320}
19321
19322DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
19323 duk_tval tv;
19324 DUK_ASSERT_CTX_VALID(ctx);
19325 DUK_ASSERT(h != NULL);
19326 DUK_TVAL_SET_STRING(&tv, h);
19327 duk_push_tval(ctx, &tv);
19328}
19329
19330DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx) {
19331 duk_hthread *thr = (duk_hthread *) ctx;
19332 DUK_UNREF(thr);
19333 DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
19334 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
19335}
19336
19337DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
19338 duk_tval tv;
19339 DUK_ASSERT_CTX_VALID(ctx);
19340 DUK_ASSERT(h != NULL);
19341 DUK_TVAL_SET_OBJECT(&tv, h);
19342 duk_push_tval(ctx, &tv);
19343}
19344
19345DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
19346 duk_tval tv;
19347 DUK_ASSERT_CTX_VALID(ctx);
19348 DUK_ASSERT(h != NULL);
19349 DUK_TVAL_SET_BUFFER(&tv, h);
19350 duk_push_tval(ctx, &tv);
19351}
19352
19353DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) {
19354 duk_hthread *thr = (duk_hthread *) ctx;
19355 DUK_ASSERT_CTX_VALID(ctx);
19356 DUK_ASSERT(thr != NULL);
19357 DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
19358 DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
19359 duk_push_hobject(ctx, thr->builtins[builtin_idx]);
19360}
19361
19362/*
19363 * Poppers
19364 */
19365
19366DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
19367 duk_hthread *thr = (duk_hthread *) ctx;
19368 duk_tval *tv;
19369
19370 DUK_ASSERT_CTX_VALID(ctx);
19371
19372 if (DUK_UNLIKELY(count < 0)) {
19373 DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
19374 return;
19375 }
19376
19377 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19378 if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
19379 DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
19380 }
19381
19382 /*
19383 * Must be very careful here, every DECREF may cause reallocation
19384 * of our valstack.
19385 */
19386
19387 /* XXX: inlined DECREF macro would be nice here: no NULL check,
19388 * refzero queueing but no refzero algorithm run (= no pointer
19389 * instability), inline code.
19390 */
19391
19392 /* XXX: optimize loops */
19393
19394#if defined(DUK_USE_REFERENCE_COUNTING)
19395 while (count > 0) {
19396 count--;
19397 tv = --thr->valstack_top; /* tv points to element just below prev top */
19398 DUK_ASSERT(tv >= thr->valstack_bottom);
19399 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
19400 }
19401#else
19402 tv = thr->valstack_top;
19403 while (count > 0) {
19404 count--;
19405 tv--;
19406 DUK_ASSERT(tv >= thr->valstack_bottom);
19407 DUK_TVAL_SET_UNDEFINED(tv);
19408 }
19409 thr->valstack_top = tv;
19410#endif
19411
19412 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19413}
19414
19415/* Popping one element is called so often that when footprint is not an issue,
19416 * compile a specialized function for it.
19417 */
19418#if defined(DUK_USE_PREFER_SIZE)
19419DUK_EXTERNAL void duk_pop(duk_context *ctx) {
19420 DUK_ASSERT_CTX_VALID(ctx);
19421 duk_pop_n(ctx, 1);
19422}
19423#else
19424DUK_EXTERNAL void duk_pop(duk_context *ctx) {
19425 duk_hthread *thr = (duk_hthread *) ctx;
19426 duk_tval *tv;
19427 DUK_ASSERT_CTX_VALID(ctx);
19428
19429 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19430 if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
19431 DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
19432 }
19433
19434 tv = --thr->valstack_top; /* tv points to element just below prev top */
19435 DUK_ASSERT(tv >= thr->valstack_bottom);
19436#ifdef DUK_USE_REFERENCE_COUNTING
19437 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
19438#else
19439 DUK_TVAL_SET_UNDEFINED(tv);
19440#endif
19441 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19442}
19443#endif /* !DUK_USE_PREFER_SIZE */
19444
19445DUK_EXTERNAL void duk_pop_2(duk_context *ctx) {
19446 DUK_ASSERT_CTX_VALID(ctx);
19447 duk_pop_n(ctx, 2);
19448}
19449
19450DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
19451 DUK_ASSERT_CTX_VALID(ctx);
19452 duk_pop_n(ctx, 3);
19453}
19454
19455/*
19456 * Error throwing
19457 */
19458
19459DUK_EXTERNAL void duk_throw(duk_context *ctx) {
19460 duk_hthread *thr = (duk_hthread *) ctx;
19461
19462 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
19463 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19464 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
19465
19466 if (thr->valstack_top == thr->valstack_bottom) {
19467 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
19468 }
19469
19470 /* Errors are augmented when they are created, not when they are
19471 * thrown or re-thrown. The current error handler, however, runs
19472 * just before an error is thrown.
19473 */
19474
19475 /* Sync so that augmentation sees up-to-date activations, NULL
19476 * thr->ptr_curr_pc so that it's not used if side effects occur
19477 * in augmentation or longjmp handling.
19478 */
19479 duk_hthread_sync_and_null_currpc(thr);
19480
19481#if defined(DUK_USE_AUGMENT_ERROR_THROW)
19482 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
19483 duk_err_augment_error_throw(thr);
19484#endif
19485 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
19486
19487 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
19488
19489 /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
19490 * need to check that here. If the value is NULL, a panic occurs because
19491 * we can't return.
19492 */
19493
19494 duk_err_longjmp(thr);
19495 DUK_UNREACHABLE();
19496}
19497
19498DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg) {
19499 duk_hthread *thr = (duk_hthread *) ctx;
19500
19501 DUK_ASSERT_CTX_VALID(ctx);
19502 DUK_ASSERT(thr != NULL);
19503 DUK_ASSERT(thr->heap != NULL);
19504 DUK_ASSERT(thr->heap->fatal_func != NULL);
19505
19506 DUK_D(DUK_DPRINT("fatal error occurred, code %ld, message %s",
19507 (long) err_code, (const char *) err_msg));
19508
19509 /* fatal_func should be noreturn, but noreturn declarations on function
19510 * pointers has a very spotty support apparently so it's not currently
19511 * done.
19512 */
19513 thr->heap->fatal_func(ctx, err_code, err_msg);
19514
19515 DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned");
19516}
19517
19518DUK_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) {
19519 DUK_ASSERT_CTX_VALID(ctx);
19520
19521 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19522 duk_throw(ctx);
19523}
19524
19525DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
19526 va_list ap;
19527
19528 DUK_ASSERT_CTX_VALID(ctx);
19529
19530 va_start(ap, fmt);
19531 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19532 va_end(ap);
19533 duk_throw(ctx);
19534}
19535
19536#if !defined(DUK_USE_VARIADIC_MACROS)
19537DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
19538 const char *filename;
19539 duk_int_t line;
19540 va_list ap;
19541
19542 DUK_ASSERT_CTX_VALID(ctx);
19543
19544 filename = duk_api_global_filename;
19545 line = duk_api_global_line;
19546 duk_api_global_filename = NULL;
19547 duk_api_global_line = 0;
19548
19549 va_start(ap, fmt);
19550 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19551 va_end(ap);
19552 duk_throw(ctx);
19553}
19554#endif /* DUK_USE_VARIADIC_MACROS */
19555
19556/*
19557 * Comparison
19558 */
19559
19560DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
19561 duk_hthread *thr = (duk_hthread *) ctx;
19562 duk_tval *tv1, *tv2;
19563
19564 DUK_ASSERT_CTX_VALID(ctx);
19565
19566 tv1 = duk_get_tval(ctx, index1);
19567 tv2 = duk_get_tval(ctx, index2);
19568 if ((tv1 == NULL) || (tv2 == NULL)) {
19569 return 0;
19570 }
19571
19572 /* Coercion may be needed, the helper handles that by pushing the
19573 * tagged values to the stack.
19574 */
19575 return duk_js_equals(thr, tv1, tv2);
19576}
19577
19578DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
19579 duk_tval *tv1, *tv2;
19580
19581 DUK_ASSERT_CTX_VALID(ctx);
19582
19583 tv1 = duk_get_tval(ctx, index1);
19584 tv2 = duk_get_tval(ctx, index2);
19585 if ((tv1 == NULL) || (tv2 == NULL)) {
19586 return 0;
19587 }
19588
19589 /* No coercions or other side effects, so safe */
19590 return duk_js_strict_equals(tv1, tv2);
19591}
19592
19593/*
19594 * instanceof
19595 */
19596
19597DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
19598 duk_tval *tv1, *tv2;
19599
19600 DUK_ASSERT_CTX_VALID(ctx);
19601
19602 /* Index validation is strict, which differs from duk_equals().
19603 * The strict behavior mimics how instanceof itself works, e.g.
19604 * it is a TypeError if rval is not a -callable- object. It would
19605 * be somewhat inconsistent if rval would be allowed to be
19606 * non-existent without a TypeError.
19607 */
19608 tv1 = duk_require_tval(ctx, index1);
19609 DUK_ASSERT(tv1 != NULL);
19610 tv2 = duk_require_tval(ctx, index2);
19611 DUK_ASSERT(tv2 != NULL);
19612
19613 return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2);
19614}
19615
19616/*
19617 * Lightfunc
19618 */
19619
19620DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
19621 duk_c_function func;
19622
19623 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
19624
19625 /* Lightfunc name, includes Duktape/C native function pointer, which
19626 * can often be used to locate the function from a symbol table.
19627 * The name also includes the 16-bit duk_tval flags field because it
19628 * includes the magic value. Because a single native function often
19629 * provides different functionality depending on the magic value, it
19630 * seems reasonably to include it in the name.
19631 *
19632 * On the other hand, a complicated name increases string table
19633 * pressure in low memory environments (but only when function name
19634 * is accessed).
19635 */
19636
19637 func = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv);
19638 duk_push_sprintf(ctx, "light_");
19639 duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func));
19640 duk_push_sprintf(ctx, "_%04x", (unsigned int) DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv));
19641 duk_concat(ctx, 3);
19642}
19643
19644DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
19645 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
19646
19647 duk_push_string(ctx, "function ");
19648 duk_push_lightfunc_name(ctx, tv);
19649 duk_push_string(ctx, "() {\"light\"}");
19650 duk_concat(ctx, 3);
19651}
19652
19653/*
19654 * Function pointers
19655 *
19656 * Printing function pointers is non-portable, so we do that by hex printing
19657 * bytes from memory.
19658 */
19659
19660DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) {
19661 duk_uint8_t buf[32 * 2];
19662 duk_uint8_t *p, *q;
19663 duk_small_uint_t i;
19664 duk_small_uint_t t;
19665
19666 DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
19667
19668 p = buf;
19669#if defined(DUK_USE_INTEGER_LE)
19670 q = ptr + sz;
19671#else
19672 q = ptr;
19673#endif
19674 for (i = 0; i < sz; i++) {
19675#if defined(DUK_USE_INTEGER_LE)
19676 t = *(--q);
19677#else
19678 t = *(q++);
19679#endif
19680 *p++ = duk_lc_digits[t >> 4];
19681 *p++ = duk_lc_digits[t & 0x0f];
19682 }
19683
19684 duk_push_lstring(ctx, (const char *) buf, sz * 2);
19685}
19686
19687#if !defined(DUK_USE_PARANOID_ERRORS)
19688/*
19689 * Push readable string summarizing duk_tval. The operation is side effect
19690 * free and will only throw from internal errors (e.g. out of memory).
19691 * This is used by e.g. property access code to summarize a key/base safely,
19692 * and is not intended to be fast (but small and safe).
19693 */
19694
19695#define DUK__READABLE_STRING_MAXCHARS 32
19696
19697/* String sanitizer which escapes ASCII control characters and a few other
19698 * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
19699 * question marks. No errors are thrown for any input string, except in out
19700 * of memory situations.
19701 */
19702DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) {
19703 duk_hthread *thr;
19704 const duk_uint8_t *p, *p_start, *p_end;
19705 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
19706 2 /*quotes*/ + 3 /*periods*/];
19707 duk_uint8_t *q;
19708 duk_ucodepoint_t cp;
19709 duk_small_uint_t nchars;
19710
19711 DUK_ASSERT_CTX_VALID(ctx);
19712 DUK_ASSERT(h_input != NULL);
19713 thr = (duk_hthread *) ctx;
19714
19715 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
19716 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
19717 p = p_start;
19718 q = buf;
19719
19720 nchars = 0;
19721 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
19722 for (;;) {
19723 if (p >= p_end) {
19724 break;
19725 }
19726 if (nchars == DUK__READABLE_STRING_MAXCHARS) {
19727 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
19728 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
19729 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
19730 break;
19731 }
19732 if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
19733 if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) {
19734 DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */
19735 DUK_ASSERT((cp >> 4) <= 0x0f);
19736 *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH;
19737 *q++ = (duk_uint8_t) DUK_ASC_LC_X;
19738 *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4];
19739 *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f];
19740 } else {
19741 q += duk_unicode_encode_xutf8(cp, q);
19742 }
19743 } else {
19744 p++; /* advance manually */
19745 *q++ = (duk_uint8_t) DUK_ASC_QUESTION;
19746 }
19747 nchars++;
19748 }
19749 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
19750
19751 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
19752}
19753
19754DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
19755 duk_hthread *thr;
19756
19757 DUK_ASSERT_CTX_VALID(ctx);
19758 thr = (duk_hthread *) ctx;
19759 DUK_UNREF(thr);
19760
19761 if (tv == NULL) {
19762 duk_push_string(ctx, "none");
19763 } else {
19764 switch (DUK_TVAL_GET_TAG(tv)) {
19765 case DUK_TAG_STRING: {
19766 duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
19767 break;
19768 }
19769 case DUK_TAG_OBJECT: {
19770 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
19771 DUK_ASSERT(h != NULL);
19772 duk_push_hobject_class_string(ctx, h);
19773 break;
19774 }
19775 case DUK_TAG_BUFFER: {
19776 /* XXX: Hex encoded, length limited buffer summary here? */
19777 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
19778 DUK_ASSERT(h != NULL);
19779 duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
19780 break;
19781 }
19782 case DUK_TAG_POINTER: {
19783 /* Surround with parentheses like in JX, ensures NULL pointer
19784 * is distinguishable from null value ("(null)" vs "null").
19785 */
19786 duk_push_tval(ctx, tv);
19787 duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1));
19788 duk_remove(ctx, -2);
19789 break;
19790 }
19791 default: {
19792 duk_push_tval(ctx, tv);
19793 break;
19794 }
19795 }
19796 }
19797
19798 return duk_to_string(ctx, -1);
19799}
19800
19801DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) {
19802 DUK_ASSERT_CTX_VALID(ctx);
19803 return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index));
19804}
19805#endif /* !DUK_USE_PARANOID_ERRORS */
19806
19807#undef DUK__CHECK_SPACE
19808#undef DUK__PACK_ARGS
19809#undef DUK__READABLE_STRING_MAXCHARS
19810#line 1 "duk_api_string.c"
19811/*
19812 * String manipulation
19813 */
19814
19815/* include removed: duk_internal.h */
19816
19817DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) {
19818 duk_hthread *thr = (duk_hthread *) ctx;
19819 duk_uint_t count;
19820 duk_uint_t i;
19821 duk_size_t idx;
19822 duk_size_t len;
19823 duk_hstring *h;
19824 duk_uint8_t *buf;
19825
19826 DUK_ASSERT_CTX_VALID(ctx);
19827
19828 if (DUK_UNLIKELY(count_in <= 0)) {
19829 if (count_in < 0) {
19830 DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
19831 return;
19832 }
19833 DUK_ASSERT(count_in == 0);
19834 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
19835 return;
19836 }
19837 count = (duk_uint_t) count_in;
19838
19839 if (is_join) {
19840 duk_size_t t1, t2, limit;
19841 h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1);
19842 DUK_ASSERT(h != NULL);
19843
19844 /* A bit tricky overflow test, see doc/code-issues.rst. */
19845 t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
19846 t2 = (duk_size_t) (count - 1);
19847 limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
19848 if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
19849 /* Combined size of separators already overflows */
19850 goto error_overflow;
19851 }
19852 len = (duk_size_t) (t1 * t2);
19853 } else {
19854 len = (duk_size_t) 0;
19855 }
19856
19857 for (i = count; i >= 1; i--) {
19858 duk_size_t new_len;
19859 duk_to_string(ctx, -((duk_idx_t) i));
19860 h = duk_require_hstring(ctx, -((duk_idx_t) i));
19861 new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
19862
19863 /* Impose a string maximum length, need to handle overflow
19864 * correctly.
19865 */
19866 if (new_len < len || /* wrapped */
19867 new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) {
19868 goto error_overflow;
19869 }
19870 len = new_len;
19871 }
19872
19873 DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
19874 (unsigned long) count, (unsigned long) len));
19875
19876 /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */
19877 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len);
19878 DUK_ASSERT(buf != NULL);
19879
19880 /* [... (sep) str1 str2 ... strN buf] */
19881
19882 idx = 0;
19883 for (i = count; i >= 1; i--) {
19884 if (is_join && i != count) {
19885 h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
19886 DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
19887 idx += DUK_HSTRING_GET_BYTELEN(h);
19888 }
19889 h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
19890 DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
19891 idx += DUK_HSTRING_GET_BYTELEN(h);
19892 }
19893
19894 DUK_ASSERT(idx == len);
19895
19896 /* [... (sep) str1 str2 ... strN buf] */
19897
19898 /* get rid of the strings early to minimize memory use before intern */
19899
19900 if (is_join) {
19901 duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */
19902 duk_pop_n(ctx, count);
19903 } else {
19904 duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */
19905 duk_pop_n(ctx, count-1);
19906 }
19907
19908 /* [... buf] */
19909
19910 (void) duk_to_string(ctx, -1);
19911
19912 /* [... res] */
19913 return;
19914
19915 error_overflow:
19916 DUK_ERROR_RANGE(thr, DUK_STR_CONCAT_RESULT_TOO_LONG);
19917}
19918
19919DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
19920 DUK_ASSERT_CTX_VALID(ctx);
19921
19922 duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
19923}
19924
19925DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) {
19926 DUK_ASSERT_CTX_VALID(ctx);
19927
19928 duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
19929}
19930
19931/* XXX: could map/decode be unified with duk_unicode_support.c code?
19932 * Case conversion needs also the character surroundings though.
19933 */
19934
19935DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata) {
19936 duk_hthread *thr = (duk_hthread *) ctx;
19937 duk_hstring *h_input;
19938 const duk_uint8_t *p, *p_start, *p_end;
19939 duk_codepoint_t cp;
19940
19941 DUK_ASSERT_CTX_VALID(ctx);
19942
19943 h_input = duk_require_hstring(ctx, index);
19944 DUK_ASSERT(h_input != NULL);
19945
19946 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
19947 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
19948 p = p_start;
19949
19950 for (;;) {
19951 if (p >= p_end) {
19952 break;
19953 }
19954 cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
19955 callback(udata, cp);
19956 }
19957}
19958
19959DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata) {
19960 duk_hthread *thr = (duk_hthread *) ctx;
19961 duk_hstring *h_input;
19962 duk_bufwriter_ctx bw_alloc;
19963 duk_bufwriter_ctx *bw;
19964 const duk_uint8_t *p, *p_start, *p_end;
19965 duk_codepoint_t cp;
19966
19967 DUK_ASSERT_CTX_VALID(ctx);
19968
19969 index = duk_normalize_index(ctx, index);
19970
19971 h_input = duk_require_hstring(ctx, index);
19972 DUK_ASSERT(h_input != NULL);
19973
19974 bw = &bw_alloc;
19975 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */
19976
19977 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
19978 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
19979 p = p_start;
19980
19981 for (;;) {
19982 /* XXX: could write output in chunks with fewer ensure calls,
19983 * but relative benefit would be small here.
19984 */
19985
19986 if (p >= p_end) {
19987 break;
19988 }
19989 cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
19990 cp = callback(udata, cp);
19991
19992 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
19993 }
19994
19995 DUK_BW_COMPACT(thr, bw);
19996 duk_to_string(ctx, -1);
19997 duk_replace(ctx, index);
19998}
19999
20000DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_offset, duk_size_t end_offset) {
20001 duk_hthread *thr = (duk_hthread *) ctx;
20002 duk_hstring *h;
20003 duk_hstring *res;
20004 duk_size_t start_byte_offset;
20005 duk_size_t end_byte_offset;
20006
20007 DUK_ASSERT_CTX_VALID(ctx);
20008
20009 index = duk_require_normalize_index(ctx, index);
20010 h = duk_require_hstring(ctx, index);
20011 DUK_ASSERT(h != NULL);
20012
20013 if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
20014 end_offset = DUK_HSTRING_GET_CHARLEN(h);
20015 }
20016 if (start_offset > end_offset) {
20017 start_offset = end_offset;
20018 }
20019
20020 DUK_ASSERT_DISABLE(start_offset >= 0);
20021 DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
20022 DUK_ASSERT_DISABLE(end_offset >= 0);
20023 DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
20024
20025 /* guaranteed by string limits */
20026 DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
20027 DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
20028
20029 start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset);
20030 end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
20031
20032 DUK_ASSERT(end_byte_offset >= start_byte_offset);
20033 DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* guaranteed by string limits */
20034
20035 /* no size check is necessary */
20036 res = duk_heap_string_intern_checked(thr,
20037 DUK_HSTRING_GET_DATA(h) + start_byte_offset,
20038 (duk_uint32_t) (end_byte_offset - start_byte_offset));
20039
20040 duk_push_hstring(ctx, res);
20041 duk_replace(ctx, index);
20042}
20043
20044/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
20045 * forwards with a callback to process codepoints?
20046 */
20047DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
20048 duk_hthread *thr = (duk_hthread *) ctx;
20049 duk_hstring *h;
20050 const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
20051 const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
20052 duk_codepoint_t cp;
20053
20054 DUK_ASSERT_CTX_VALID(ctx);
20055
20056 index = duk_require_normalize_index(ctx, index);
20057 h = duk_require_hstring(ctx, index);
20058 DUK_ASSERT(h != NULL);
20059
20060 p_start = DUK_HSTRING_GET_DATA(h);
20061 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
20062
20063 p = p_start;
20064 while (p < p_end) {
20065 p_tmp1 = p;
20066 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
20067 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
20068 break;
20069 }
20070 p = p_tmp1;
20071 }
20072 q_start = p;
20073 if (p == p_end) {
20074 /* entire string is whitespace */
20075 q_end = p;
20076 goto scan_done;
20077 }
20078
20079 p = p_end;
20080 while (p > p_start) {
20081 p_tmp1 = p;
20082 while (p > p_start) {
20083 p--;
20084 if (((*p) & 0xc0) != 0x80) {
20085 break;
20086 }
20087 }
20088 p_tmp2 = p;
20089
20090 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
20091 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
20092 p = p_tmp1;
20093 break;
20094 }
20095 }
20096 q_end = p;
20097
20098 scan_done:
20099 /* This may happen when forward and backward scanning disagree
20100 * (possible for non-extended-UTF-8 strings).
20101 */
20102 if (q_end < q_start) {
20103 q_end = q_start;
20104 }
20105
20106 DUK_ASSERT(q_start >= p_start && q_start <= p_end);
20107 DUK_ASSERT(q_end >= p_start && q_end <= p_end);
20108 DUK_ASSERT(q_end >= q_start);
20109
20110 DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
20111 (const void *) p_start, (const void *) p_end,
20112 (const void *) q_start, (const void *) q_end));
20113
20114 if (q_start == p_start && q_end == p_end) {
20115 DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
20116 return;
20117 }
20118
20119 duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start));
20120 duk_replace(ctx, index);
20121}
20122
20123DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset) {
20124 duk_hthread *thr = (duk_hthread *) ctx;
20125 duk_hstring *h;
20126 duk_ucodepoint_t cp;
20127
20128 DUK_ASSERT_CTX_VALID(ctx);
20129
20130 h = duk_require_hstring(ctx, index);
20131 DUK_ASSERT(h != NULL);
20132
20133 DUK_ASSERT_DISABLE(char_offset >= 0); /* always true, arg is unsigned */
20134 if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
20135 return 0;
20136 }
20137
20138 DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* guaranteed by string limits */
20139 cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset);
20140 return (duk_codepoint_t) cp;
20141}
20142#line 1 "duk_api_var.c"
20143/*
20144 * Variable access
20145 */
20146
20147/* include removed: duk_internal.h */
20148
20149DUK_EXTERNAL void duk_get_var(duk_context *ctx) {
20150 duk_hthread *thr = (duk_hthread *) ctx;
20151 duk_activation *act;
20152 duk_hstring *h_varname;
20153 duk_small_int_t throw_flag = 1; /* always throw ReferenceError for unresolvable */
20154
20155 DUK_ASSERT_CTX_VALID(ctx);
20156
20157 h_varname = duk_require_hstring(ctx, -1); /* XXX: tostring? */
20158 DUK_ASSERT(h_varname != NULL);
20159
20160 act = duk_hthread_get_current_activation(thr);
20161 if (act) {
20162 (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag); /* -> [ ... varname val this ] */
20163 } else {
20164 /* Outside any activation -> look up from global. */
20165 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
20166 (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag);
20167 }
20168
20169 /* [ ... varname val this ] (because throw_flag == 1, always resolved) */
20170
20171 duk_pop(ctx);
20172 duk_remove(ctx, -2);
20173
20174 /* [ ... val ] */
20175
20176 /* Return value would be pointless: because throw_flag==1, we always
20177 * throw if the identifier doesn't resolve.
20178 */
20179 return;
20180}
20181
20182DUK_EXTERNAL void duk_put_var(duk_context *ctx) {
20183 duk_hthread *thr = (duk_hthread *) ctx;
20184 duk_activation *act;
20185 duk_hstring *h_varname;
20186 duk_tval *tv_val;
20187 duk_small_int_t throw_flag;
20188
20189 DUK_ASSERT_CTX_VALID(ctx);
20190
20191 h_varname = duk_require_hstring(ctx, -2); /* XXX: tostring? */
20192 DUK_ASSERT(h_varname != NULL);
20193
20194 tv_val = duk_require_tval(ctx, -1);
20195
20196 throw_flag = duk_is_strict_call(ctx);
20197
20198 act = duk_hthread_get_current_activation(thr);
20199 if (act) {
20200 duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag); /* -> [ ... varname val this ] */
20201 } else {
20202 /* Outside any activation -> put to global. */
20203 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
20204 duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag);
20205 }
20206
20207 /* [ ... varname val ] */
20208
20209 duk_pop_2(ctx);
20210
20211 /* [ ... ] */
20212
20213 return;
20214}
20215
20216DUK_EXTERNAL duk_bool_t duk_del_var(duk_context *ctx) {
20217 DUK_ASSERT_CTX_VALID(ctx);
20218
20219 DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
20220 return 0;
20221}
20222
20223DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
20224 DUK_ASSERT_CTX_VALID(ctx);
20225
20226 DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
20227 return 0;
20228}
20229#line 1 "duk_bi_array.c"
20230/*
20231 * Array built-ins
20232 *
20233 * Note that most Array built-ins are intentionally generic and work even
20234 * when the 'this' binding is not an Array instance. To ensure this,
20235 * Array algorithms do not assume "magical" Array behavior for the "length"
20236 * property, for instance.
20237 *
20238 * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
20239 * [[Delete]] operations, but it's currently false throughout. Go through
20240 * all put/delete cases and check throw flag use. Need a new API primitive
20241 * which allows throws flag to be specified.
20242 *
20243 * XXX: array lengths above 2G won't work reliably. There are many places
20244 * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff],
20245 * i.e. -33- bits). Although array 'length' cannot be written to be outside
20246 * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
20247 * some intermediate values may be above 0xffffffff and this may not be always
20248 * correctly handled now (duk_uint32_t is not enough for all algorithms).
20249 *
20250 * For instance, push() can legitimately write entries beyond length 0xffffffff
20251 * and cause a RangeError only at the end. To do this properly, the current
20252 * push() implementation tracks the array index using a 'double' instead of a
20253 * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js.
20254 *
20255 * On using "put" vs. "def" prop
20256 * =============================
20257 *
20258 * Code below must be careful to use the appropriate primitive as it matters
20259 * for compliance. When using "put" there may be inherited properties in
20260 * Array.prototype which cause side effects when values are written. When
20261 * using "define" there are no such side effects, and many test262 test cases
20262 * check for this (for real world code, such side effects are very rare).
20263 * Both "put" and "define" are used in the E5.1 specification; as a rule,
20264 * "put" is used when modifying an existing array (or a non-array 'this'
20265 * binding) and "define" for setting values into a fresh result array.
20266 *
20267 * Also note that Array instance 'length' should be writable, but not
20268 * enumerable and definitely not configurable: even Duktape code internally
20269 * assumes that an Array instance will always have a 'length' property.
20270 * Preventing deletion of the property is critical.
20271 */
20272
20273/* include removed: duk_internal.h */
20274
20275/* Perform an intermediate join when this many elements have been pushed
20276 * on the value stack.
20277 */
20278#define DUK__ARRAY_MID_JOIN_LIMIT 4096
20279
20280/* Shared entry code for many Array built-ins. Note that length is left
20281 * on stack (it could be popped, but that's not necessary).
20282 */
20283DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) {
20284 duk_uint32_t len;
20285
20286 (void) duk_push_this_coercible_to_object(ctx);
20287 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
20288 len = duk_to_uint32(ctx, -1);
20289
20290 /* -> [ ... ToObject(this) ToUint32(length) ] */
20291 return len;
20292}
20293
20294DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
20295 /* Range limited to [0, 0x7fffffff] range, i.e. range that can be
20296 * represented with duk_int32_t. Use this when the method doesn't
20297 * handle the full 32-bit unsigned range correctly.
20298 */
20299 duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
20300 if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
20301 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_ARRAY_LENGTH_OVER_2G);
20302 }
20303 return ret;
20304}
20305
20306/*
20307 * Constructor
20308 */
20309
20310DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
20311 duk_idx_t nargs;
20312 duk_double_t d;
20313 duk_uint32_t len;
20314 duk_idx_t i;
20315
20316 nargs = duk_get_top(ctx);
20317 duk_push_array(ctx);
20318
20319 if (nargs == 1 && duk_is_number(ctx, 0)) {
20320 /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
20321 d = duk_get_number(ctx, 0);
20322 len = duk_to_uint32(ctx, 0);
20323 if (((duk_double_t) len) != d) {
20324 return DUK_RET_RANGE_ERROR;
20325 }
20326
20327 /* XXX: if 'len' is low, may want to ensure array part is kept:
20328 * the caller is likely to want a dense array.
20329 */
20330 duk_push_u32(ctx, len);
20331 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */
20332 return 1;
20333 }
20334
20335 /* XXX: optimize by creating array into correct size directly, and
20336 * operating on the array part directly; values can be memcpy()'d from
20337 * value stack directly as long as refcounts are increased.
20338 */
20339 for (i = 0; i < nargs; i++) {
20340 duk_dup(ctx, i);
20341 duk_xdef_prop_index_wec(ctx, -2, (duk_uarridx_t) i);
20342 }
20343
20344 duk_push_u32(ctx, (duk_uint32_t) nargs);
20345 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
20346 return 1;
20347}
20348
20349/*
20350 * isArray()
20351 */
20352
20353DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
20354 duk_hobject *h;
20355
20356 h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
20357 duk_push_boolean(ctx, (h != NULL));
20358 return 1;
20359}
20360
20361/*
20362 * toString()
20363 */
20364
20365DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
20366 (void) duk_push_this_coercible_to_object(ctx);
20367 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN);
20368
20369 /* [ ... this func ] */
20370 if (!duk_is_callable(ctx, -1)) {
20371 /* Fall back to the initial (original) Object.toString(). We don't
20372 * currently have pointers to the built-in functions, only the top
20373 * level global objects (like "Array") so this is now done in a bit
20374 * of a hacky manner. It would be cleaner to push the (original)
20375 * function and use duk_call_method().
20376 */
20377
20378 /* XXX: 'this' will be ToObject() coerced twice, which is incorrect
20379 * but should have no visible side effects.
20380 */
20381 DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
20382 duk_set_top(ctx, 0);
20383 return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */
20384 }
20385
20386 /* [ ... this func ] */
20387
20388 duk_insert(ctx, -2);
20389
20390 /* [ ... func this ] */
20391
20392 DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
20393 (duk_tval *) duk_get_tval(ctx, -2),
20394 (duk_tval *) duk_get_tval(ctx, -1)));
20395 duk_call_method(ctx, 0);
20396
20397 return 1;
20398}
20399
20400/*
20401 * concat()
20402 */
20403
20404DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
20405 duk_idx_t i, n;
20406 duk_uarridx_t idx, idx_last;
20407 duk_uarridx_t j, len;
20408 duk_hobject *h;
20409
20410 /* XXX: the insert here is a bit expensive if there are a lot of items.
20411 * It could also be special cased in the outermost for loop quite easily
20412 * (as the element is dup()'d anyway).
20413 */
20414
20415 (void) duk_push_this_coercible_to_object(ctx);
20416 duk_insert(ctx, 0);
20417 n = duk_get_top(ctx);
20418 duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
20419
20420 /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
20421 * (which differs from the official algorithm). If no error is thrown, this
20422 * doesn't matter as the length is updated at the end. However, if an error
20423 * is thrown, the length will be unset. That shouldn't matter because the
20424 * caller won't get a reference to the intermediate value.
20425 */
20426
20427 idx = 0;
20428 idx_last = 0;
20429 for (i = 0; i < n; i++) {
20430 DUK_ASSERT_TOP(ctx, n + 1);
20431
20432 /* [ ToObject(this) item1 ... itemN arr ] */
20433
20434 duk_dup(ctx, i);
20435 h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
20436 if (!h) {
20437 duk_xdef_prop_index_wec(ctx, -2, idx++);
20438 idx_last = idx;
20439 continue;
20440 }
20441
20442 /* [ ToObject(this) item1 ... itemN arr item(i) ] */
20443
20444 /* XXX: an array can have length higher than 32 bits; this is not handled
20445 * correctly now.
20446 */
20447 len = (duk_uarridx_t) duk_get_length(ctx, -1);
20448 for (j = 0; j < len; j++) {
20449 if (duk_get_prop_index(ctx, -1, j)) {
20450 /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
20451 duk_xdef_prop_index_wec(ctx, -3, idx++);
20452 idx_last = idx;
20453 } else {
20454 idx++;
20455 duk_pop(ctx);
20456#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
20457 /* According to E5.1 Section 15.4.4.4 nonexistent trailing
20458 * elements do not affect 'length' of the result. Test262
20459 * and other engines disagree, so update idx_last here too.
20460 */
20461 idx_last = idx;
20462#else
20463 /* Strict standard behavior, ignore trailing elements for
20464 * result 'length'.
20465 */
20466#endif
20467 }
20468 }
20469 duk_pop(ctx);
20470 }
20471
20472 /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
20473 * in the end, but because we're operating with an internal value which
20474 * is known to be an array, this should be equivalent.
20475 */
20476 duk_push_uarridx(ctx, idx_last);
20477 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
20478
20479 DUK_ASSERT_TOP(ctx, n + 1);
20480 return 1;
20481}
20482
20483/*
20484 * join(), toLocaleString()
20485 *
20486 * Note: checking valstack is necessary, but only in the per-element loop.
20487 *
20488 * Note: the trivial approach of pushing all the elements on the value stack
20489 * and then calling duk_join() fails when the array contains a large number
20490 * of elements. This problem can't be offloaded to duk_join() because the
20491 * elements to join must be handled here and have special handling. Current
20492 * approach is to do intermediate joins with very large number of elements.
20493 * There is no fancy handling; the prefix gets re-joined multiple times.
20494 */
20495
20496DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
20497 duk_uint32_t len, count;
20498 duk_uint32_t idx;
20499 duk_small_int_t to_locale_string = duk_get_current_magic(ctx);
20500 duk_idx_t valstack_required;
20501
20502 /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
20503 * setting the top essentially pushes an undefined to the stack,
20504 * thus defaulting to a comma separator.
20505 */
20506 duk_set_top(ctx, 1);
20507 if (duk_is_undefined(ctx, 0)) {
20508 duk_pop(ctx);
20509 duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
20510 } else {
20511 duk_to_string(ctx, 0);
20512 }
20513
20514 len = duk__push_this_obj_len_u32(ctx);
20515
20516 /* [ sep ToObject(this) len ] */
20517
20518 DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
20519 (duk_tval *) duk_get_tval(ctx, 0),
20520 (duk_tval *) duk_get_tval(ctx, 1),
20521 (unsigned long) len));
20522
20523 /* The extra (+4) is tight. */
20524 valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
20525 DUK__ARRAY_MID_JOIN_LIMIT : len) + 4;
20526 duk_require_stack(ctx, valstack_required);
20527
20528 duk_dup(ctx, 0);
20529
20530 /* [ sep ToObject(this) len sep ] */
20531
20532 count = 0;
20533 idx = 0;
20534 for (;;) {
20535 if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */
20536 idx >= len) { /* end of loop (careful with len==0) */
20537 /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
20538 DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
20539 (long) count, (long) idx, (long) len));
20540 duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
20541 duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */
20542 duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */
20543 count = 1;
20544 }
20545 if (idx >= len) {
20546 /* if true, the stack already contains the final result */
20547 break;
20548 }
20549
20550 duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx);
20551 if (duk_is_null_or_undefined(ctx, -1)) {
20552 duk_pop(ctx);
20553 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
20554 } else {
20555 if (to_locale_string) {
20556 duk_to_object(ctx, -1);
20557 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
20558 duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */
20559 duk_call_method(ctx, 0);
20560 duk_to_string(ctx, -1);
20561 } else {
20562 duk_to_string(ctx, -1);
20563 }
20564 }
20565
20566 count++;
20567 idx++;
20568 }
20569
20570 /* [ sep ToObject(this) len sep result ] */
20571
20572 return 1;
20573}
20574
20575/*
20576 * pop(), push()
20577 */
20578
20579DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) {
20580 duk_uint32_t len;
20581 duk_uint32_t idx;
20582
20583 DUK_ASSERT_TOP(ctx, 0);
20584 len = duk__push_this_obj_len_u32(ctx);
20585 if (len == 0) {
20586 duk_push_int(ctx, 0);
20587 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
20588 return 0;
20589 }
20590 idx = len - 1;
20591
20592 duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx);
20593 duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx);
20594 duk_push_u32(ctx, idx);
20595 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
20596 return 1;
20597}
20598
20599DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
20600 /* Note: 'this' is not necessarily an Array object. The push()
20601 * algorithm is supposed to work for other kinds of objects too,
20602 * so the algorithm has e.g. an explicit update for the 'length'
20603 * property which is normally "magical" in arrays.
20604 */
20605
20606 duk_uint32_t len;
20607 duk_idx_t i, n;
20608
20609 n = duk_get_top(ctx);
20610 len = duk__push_this_obj_len_u32(ctx);
20611
20612 /* [ arg1 ... argN obj length ] */
20613
20614 /* Technically Array.prototype.push() can create an Array with length
20615 * longer than 2^32-1, i.e. outside the 32-bit range. The final length
20616 * is *not* wrapped to 32 bits in the specification.
20617 *
20618 * This implementation tracks length with a uint32 because it's much
20619 * more practical.
20620 *
20621 * See: test-bi-array-push-maxlen.js.
20622 */
20623
20624 if (len + (duk_uint32_t) n < len) {
20625 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
20626 return DUK_RET_RANGE_ERROR;
20627 }
20628
20629 for (i = 0; i < n; i++) {
20630 duk_dup(ctx, i);
20631 duk_put_prop_index(ctx, -3, len + i);
20632 }
20633 len += n;
20634
20635 duk_push_u32(ctx, len);
20636 duk_dup_top(ctx);
20637 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
20638
20639 /* [ arg1 ... argN obj length new_length ] */
20640 return 1;
20641}
20642
20643/*
20644 * sort()
20645 *
20646 * Currently qsort with random pivot. This is now really, really slow,
20647 * because there is no fast path for array parts.
20648 *
20649 * Signed indices are used because qsort() leaves and degenerate cases
20650 * may use a negative offset.
20651 */
20652
20653DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) {
20654 duk_bool_t have1, have2;
20655 duk_bool_t undef1, undef2;
20656 duk_small_int_t ret;
20657 duk_idx_t idx_obj = 1; /* fixed offsets in valstack */
20658 duk_idx_t idx_fn = 0;
20659 duk_hstring *h1, *h2;
20660
20661 /* Fast exit if indices are identical. This is valid for a non-existent property,
20662 * for an undefined value, and almost always for ToString() coerced comparison of
20663 * arbitrary values (corner cases where this is not the case include e.g. a an
20664 * object with varying ToString() coercion).
20665 *
20666 * The specification does not prohibit "caching" of values read from the array, so
20667 * assuming equality for comparing an index with itself falls into the category of
20668 * "caching".
20669 *
20670 * Also, compareFn may be inconsistent, so skipping a call to compareFn here may
20671 * have an effect on the final result. The specification does not require any
20672 * specific behavior for inconsistent compare functions, so again, this fast path
20673 * is OK.
20674 */
20675
20676 if (idx1 == idx2) {
20677 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit",
20678 (long) idx1, (long) idx2));
20679 return 0;
20680 }
20681
20682 have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1);
20683 have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2);
20684
20685 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
20686 (long) idx1, (long) idx2, (long) have1, (long) have2,
20687 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
20688
20689 if (have1) {
20690 if (have2) {
20691 ;
20692 } else {
20693 ret = -1;
20694 goto pop_ret;
20695 }
20696 } else {
20697 if (have2) {
20698 ret = 1;
20699 goto pop_ret;
20700 } else {
20701 ret = 0;
20702 goto pop_ret;
20703 }
20704 }
20705
20706 undef1 = duk_is_undefined(ctx, -2);
20707 undef2 = duk_is_undefined(ctx, -1);
20708 if (undef1) {
20709 if (undef2) {
20710 ret = 0;
20711 goto pop_ret;
20712 } else {
20713 ret = 1;
20714 goto pop_ret;
20715 }
20716 } else {
20717 if (undef2) {
20718 ret = -1;
20719 goto pop_ret;
20720 } else {
20721 ;
20722 }
20723 }
20724
20725 if (!duk_is_undefined(ctx, idx_fn)) {
20726 duk_double_t d;
20727
20728 /* no need to check callable; duk_call() will do that */
20729 duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */
20730 duk_insert(ctx, -3); /* -> [ ... fn x y ] */
20731 duk_call(ctx, 2); /* -> [ ... res ] */
20732
20733 /* The specification is a bit vague what to do if the return
20734 * value is not a number. Other implementations seem to
20735 * tolerate non-numbers but e.g. V8 won't apparently do a
20736 * ToNumber().
20737 */
20738
20739 /* XXX: best behavior for real world compatibility? */
20740
20741 d = duk_to_number(ctx, -1);
20742 if (d < 0.0) {
20743 ret = -1;
20744 } else if (d > 0.0) {
20745 ret = 1;
20746 } else {
20747 ret = 0;
20748 }
20749
20750 duk_pop(ctx);
20751 DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
20752 return ret;
20753 }
20754
20755 /* string compare is the default (a bit oddly) */
20756
20757 h1 = duk_to_hstring(ctx, -2);
20758 h2 = duk_to_hstring(ctx, -1);
20759 DUK_ASSERT(h1 != NULL);
20760 DUK_ASSERT(h2 != NULL);
20761
20762 ret = duk_js_string_compare(h1, h2); /* retval is directly usable */
20763 goto pop_ret;
20764
20765 pop_ret:
20766 duk_pop_2(ctx);
20767 DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
20768 return ret;
20769}
20770
20771DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) {
20772 duk_bool_t have_l, have_r;
20773 duk_idx_t idx_obj = 1; /* fixed offset in valstack */
20774
20775 if (l == r) {
20776 return;
20777 }
20778
20779 /* swap elements; deal with non-existent elements correctly */
20780 have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
20781 have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
20782
20783 if (have_r) {
20784 /* right exists, [[Put]] regardless whether or not left exists */
20785 duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
20786 } else {
20787 duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
20788 duk_pop(ctx);
20789 }
20790
20791 if (have_l) {
20792 duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
20793 } else {
20794 duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
20795 duk_pop(ctx);
20796 }
20797}
20798
20799#if defined(DUK_USE_DDDPRINT)
20800/* Debug print which visualizes the qsort partitioning process. */
20801DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
20802 char buf[4096];
20803 char *ptr = buf;
20804 duk_int_t i, n;
20805 n = (duk_int_t) duk_get_length(ctx, 1);
20806 if (n > 4000) {
20807 n = 4000;
20808 }
20809 *ptr++ = '[';
20810 for (i = 0; i < n; i++) {
20811 if (i == pivot) {
20812 *ptr++ = '|';
20813 } else if (i == lo) {
20814 *ptr++ = '<';
20815 } else if (i == hi) {
20816 *ptr++ = '>';
20817 } else if (i >= lo && i <= hi) {
20818 *ptr++ = '-';
20819 } else {
20820 *ptr++ = ' ';
20821 }
20822 }
20823 *ptr++ = ']';
20824 *ptr++ = '\0';
20825
20826 DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)",
20827 (const char *) buf, (long) lo, (long) hi, (long) pivot));
20828}
20829#endif
20830
20831DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
20832 duk_hthread *thr = (duk_hthread *) ctx;
20833 duk_int_t p, l, r;
20834
20835 /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
20836
20837 DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
20838 (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1)));
20839
20840 DUK_ASSERT_TOP(ctx, 3);
20841
20842 /* In some cases it may be that lo > hi, or hi < 0; these
20843 * degenerate cases happen e.g. for empty arrays, and in
20844 * recursion leaves.
20845 */
20846
20847 /* trivial cases */
20848 if (hi - lo < 1) {
20849 DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately"));
20850 return;
20851 }
20852 DUK_ASSERT(hi > lo);
20853 DUK_ASSERT(hi - lo + 1 >= 2);
20854
20855 /* randomized pivot selection */
20856 p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */
20857 DUK_ASSERT(p >= lo && p <= hi);
20858 DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld",
20859 (long) lo, (long) hi, (long) p));
20860
20861 /* move pivot out of the way */
20862 duk__array_sort_swap(ctx, p, lo);
20863 p = lo;
20864 DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
20865
20866 l = lo + 1;
20867 r = hi;
20868 for (;;) {
20869 /* find elements to swap */
20870 for (;;) {
20871 DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld",
20872 (long) l, (long) r, (long) p));
20873 if (l >= hi) {
20874 break;
20875 }
20876 if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */
20877 break;
20878 }
20879 l++;
20880 }
20881 for (;;) {
20882 DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld",
20883 (long) l, (long) r, (long) p));
20884 if (r <= lo) {
20885 break;
20886 }
20887 if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */
20888 break;
20889 }
20890 r--;
20891 }
20892 if (l >= r) {
20893 goto done;
20894 }
20895 DUK_ASSERT(l < r);
20896
20897 DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
20898
20899 duk__array_sort_swap(ctx, l, r);
20900
20901 DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
20902 l++;
20903 r--;
20904 }
20905 done:
20906 /* Note that 'l' and 'r' may cross, i.e. r < l */
20907 DUK_ASSERT(l >= lo && l <= hi);
20908 DUK_ASSERT(r >= lo && r <= hi);
20909
20910 /* XXX: there's no explicit recursion bound here now. For the average
20911 * qsort recursion depth O(log n) that's not really necessary: e.g. for
20912 * 2**32 recursion depth would be about 32 which is OK. However, qsort
20913 * worst case recursion depth is O(n) which may be a problem.
20914 */
20915
20916 /* move pivot to its final place */
20917 DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
20918 duk__array_sort_swap(ctx, lo, r);
20919
20920#if defined(DUK_USE_DDDPRINT)
20921 duk__debuglog_qsort_state(ctx, lo, hi, r);
20922#endif
20923
20924 DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1)));
20925 duk__array_qsort(ctx, lo, r - 1);
20926 duk__array_qsort(ctx, r + 1, hi);
20927}
20928
20929DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
20930 duk_uint32_t len;
20931
20932 /* XXX: len >= 0x80000000 won't work below because a signed type
20933 * is needed by qsort.
20934 */
20935 len = duk__push_this_obj_len_u32_limited(ctx);
20936
20937 /* stack[0] = compareFn
20938 * stack[1] = ToObject(this)
20939 * stack[2] = ToUint32(length)
20940 */
20941
20942 if (len > 0) {
20943 /* avoid degenerate cases, so that (len - 1) won't underflow */
20944 duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1));
20945 }
20946
20947 DUK_ASSERT_TOP(ctx, 3);
20948 duk_pop(ctx);
20949 return 1; /* return ToObject(this) */
20950}
20951
20952/*
20953 * splice()
20954 */
20955
20956/* XXX: this compiles to over 500 bytes now, even without special handling
20957 * for an array part. Uses signed ints so does not handle full array range correctly.
20958 */
20959
20960/* XXX: can shift() / unshift() use the same helper?
20961 * shift() is (close to?) <--> splice(0, 1)
20962 * unshift is (close to?) <--> splice(0, 0, [items])?
20963 */
20964
20965DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
20966 duk_idx_t nargs;
20967 duk_uint32_t len;
20968 duk_bool_t have_delcount;
20969 duk_int_t item_count;
20970 duk_int_t act_start;
20971 duk_int_t del_count;
20972 duk_int_t i, n;
20973
20974 DUK_UNREF(have_delcount);
20975
20976 nargs = duk_get_top(ctx);
20977 if (nargs < 2) {
20978 duk_set_top(ctx, 2);
20979 nargs = 2;
20980 have_delcount = 0;
20981 } else {
20982 have_delcount = 1;
20983 }
20984
20985 /* XXX: len >= 0x80000000 won't work below because we need to be
20986 * able to represent -len.
20987 */
20988 len = duk__push_this_obj_len_u32_limited(ctx);
20989
20990 act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
20991 if (act_start < 0) {
20992 act_start = len + act_start;
20993 }
20994 DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
20995
20996#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
20997 if (have_delcount) {
20998#endif
20999 del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
21000#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
21001 } else {
21002 /* E5.1 standard behavior when deleteCount is not given would be
21003 * to treat it just like if 'undefined' was given, which coerces
21004 * ultimately to 0. Real world behavior is to splice to the end
21005 * of array, see test-bi-array-proto-splice-no-delcount.js.
21006 */
21007 del_count = len - act_start;
21008 }
21009#endif
21010
21011 DUK_ASSERT(nargs >= 2);
21012 item_count = (duk_int_t) (nargs - 2);
21013
21014 DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
21015 DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
21016
21017 /* For now, restrict result array into 32-bit length range. */
21018 if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
21019 DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
21020 return DUK_RET_RANGE_ERROR;
21021 }
21022
21023 duk_push_array(ctx);
21024
21025 /* stack[0] = start
21026 * stack[1] = deleteCount
21027 * stack[2...nargs-1] = items
21028 * stack[nargs] = ToObject(this) -3
21029 * stack[nargs+1] = ToUint32(length) -2
21030 * stack[nargs+2] = result array -1
21031 */
21032
21033 DUK_ASSERT_TOP(ctx, nargs + 3);
21034
21035 /* Step 9: copy elements-to-be-deleted into the result array */
21036
21037 for (i = 0; i < del_count; i++) {
21038 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
21039 duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
21040 } else {
21041 duk_pop(ctx);
21042 }
21043 }
21044 duk_push_u32(ctx, (duk_uint32_t) del_count);
21045 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
21046
21047 /* Steps 12 and 13: reorganize elements to make room for itemCount elements */
21048
21049 if (item_count < del_count) {
21050 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1
21051 * -> [ A B F G H ] (conceptual intermediate step)
21052 * -> [ A B . F G H ] (placeholder marked)
21053 * [ A B C F G H ] (actual result at this point, C will be replaced)
21054 */
21055
21056 DUK_ASSERT_TOP(ctx, nargs + 3);
21057
21058 n = len - del_count;
21059 for (i = act_start; i < n; i++) {
21060 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
21061 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
21062 } else {
21063 duk_pop(ctx);
21064 duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
21065 }
21066 }
21067
21068 DUK_ASSERT_TOP(ctx, nargs + 3);
21069
21070 /* loop iterator init and limit changed from standard algorithm */
21071 n = len - del_count + item_count;
21072 for (i = len - 1; i >= n; i--) {
21073 duk_del_prop_index(ctx, -3, (duk_uarridx_t) i);
21074 }
21075
21076 DUK_ASSERT_TOP(ctx, nargs + 3);
21077 } else if (item_count > del_count) {
21078 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
21079 * -> [ A B F G H ] (conceptual intermediate step)
21080 * -> [ A B . . . . F G H ] (placeholder marked)
21081 * [ A B C D E F F G H ] (actual result at this point)
21082 */
21083
21084 DUK_ASSERT_TOP(ctx, nargs + 3);
21085
21086 /* loop iterator init and limit changed from standard algorithm */
21087 for (i = len - del_count - 1; i >= act_start; i--) {
21088 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
21089 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
21090 } else {
21091 duk_pop(ctx);
21092 duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
21093 }
21094 }
21095
21096 DUK_ASSERT_TOP(ctx, nargs + 3);
21097 } else {
21098 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
21099 * -> [ A B F G H ] (conceptual intermediate step)
21100 * -> [ A B . . . F G H ] (placeholder marked)
21101 * [ A B C D E F G H ] (actual result at this point)
21102 */
21103 }
21104 DUK_ASSERT_TOP(ctx, nargs + 3);
21105
21106 /* Step 15: insert itemCount elements into the hole made above */
21107
21108 for (i = 0; i < item_count; i++) {
21109 duk_dup(ctx, i + 2); /* args start at index 2 */
21110 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i));
21111 }
21112
21113 /* Step 16: update length; note that the final length may be above 32 bit range
21114 * (but we checked above that this isn't the case here)
21115 */
21116
21117 duk_push_u32(ctx, len - del_count + item_count);
21118 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
21119
21120 /* result array is already at the top of stack */
21121 DUK_ASSERT_TOP(ctx, nargs + 3);
21122 return 1;
21123}
21124
21125/*
21126 * reverse()
21127 */
21128
21129DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
21130 duk_uint32_t len;
21131 duk_uint32_t middle;
21132 duk_uint32_t lower, upper;
21133 duk_bool_t have_lower, have_upper;
21134
21135 len = duk__push_this_obj_len_u32(ctx);
21136 middle = len / 2;
21137
21138 /* If len <= 1, middle will be 0 and for-loop bails out
21139 * immediately (0 < 0 -> false).
21140 */
21141
21142 for (lower = 0; lower < middle; lower++) {
21143 DUK_ASSERT(len >= 2);
21144 DUK_ASSERT_TOP(ctx, 2);
21145
21146 DUK_ASSERT(len >= lower + 1);
21147 upper = len - lower - 1;
21148
21149 have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower);
21150 have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper);
21151
21152 /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
21153
21154 if (have_upper) {
21155 duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower);
21156 } else {
21157 duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower);
21158 duk_pop(ctx);
21159 }
21160
21161 if (have_lower) {
21162 duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper);
21163 } else {
21164 duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper);
21165 duk_pop(ctx);
21166 }
21167
21168 DUK_ASSERT_TOP(ctx, 2);
21169 }
21170
21171 DUK_ASSERT_TOP(ctx, 2);
21172 duk_pop(ctx); /* -> [ ToObject(this) ] */
21173 return 1;
21174}
21175
21176/*
21177 * slice()
21178 */
21179
21180DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
21181 duk_uint32_t len;
21182 duk_int_t start, end;
21183 duk_int_t i;
21184 duk_uarridx_t idx;
21185 duk_uint32_t res_length = 0;
21186
21187 /* XXX: len >= 0x80000000 won't work below because we need to be
21188 * able to represent -len.
21189 */
21190 len = duk__push_this_obj_len_u32_limited(ctx);
21191 duk_push_array(ctx);
21192
21193 /* stack[0] = start
21194 * stack[1] = end
21195 * stack[2] = ToObject(this)
21196 * stack[3] = ToUint32(length)
21197 * stack[4] = result array
21198 */
21199
21200 start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
21201 if (start < 0) {
21202 start = len + start;
21203 }
21204 /* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
21205 * (the upper limit)?
21206 */
21207 if (duk_is_undefined(ctx, 1)) {
21208 end = len;
21209 } else {
21210 end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len);
21211 if (end < 0) {
21212 end = len + end;
21213 }
21214 }
21215 DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
21216 DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
21217
21218 idx = 0;
21219 for (i = start; i < end; i++) {
21220 DUK_ASSERT_TOP(ctx, 5);
21221 if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21222 duk_xdef_prop_index_wec(ctx, 4, idx);
21223 res_length = idx + 1;
21224 } else {
21225 duk_pop(ctx);
21226 }
21227 idx++;
21228 DUK_ASSERT_TOP(ctx, 5);
21229 }
21230
21231 duk_push_u32(ctx, res_length);
21232 duk_xdef_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
21233
21234 DUK_ASSERT_TOP(ctx, 5);
21235 return 1;
21236}
21237
21238/*
21239 * shift()
21240 */
21241
21242DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
21243 duk_uint32_t len;
21244 duk_uint32_t i;
21245
21246 len = duk__push_this_obj_len_u32(ctx);
21247 if (len == 0) {
21248 duk_push_int(ctx, 0);
21249 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
21250 return 0;
21251 }
21252
21253 duk_get_prop_index(ctx, 0, 0);
21254
21255 /* stack[0] = object (this)
21256 * stack[1] = ToUint32(length)
21257 * stack[2] = elem at index 0 (retval)
21258 */
21259
21260 for (i = 1; i < len; i++) {
21261 DUK_ASSERT_TOP(ctx, 3);
21262 if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) {
21263 /* fromPresent = true */
21264 duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
21265 } else {
21266 /* fromPresent = false */
21267 duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
21268 duk_pop(ctx);
21269 }
21270 }
21271 duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1));
21272
21273 duk_push_u32(ctx, (duk_uint32_t) (len - 1));
21274 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
21275
21276 DUK_ASSERT_TOP(ctx, 3);
21277 return 1;
21278}
21279
21280/*
21281 * unshift()
21282 */
21283
21284DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
21285 duk_idx_t nargs;
21286 duk_uint32_t len;
21287 duk_uint32_t i;
21288
21289 nargs = duk_get_top(ctx);
21290 len = duk__push_this_obj_len_u32(ctx);
21291
21292 /* stack[0...nargs-1] = unshift args (vararg)
21293 * stack[nargs] = ToObject(this)
21294 * stack[nargs+1] = ToUint32(length)
21295 */
21296
21297 DUK_ASSERT_TOP(ctx, nargs + 2);
21298
21299 /* Note: unshift() may operate on indices above unsigned 32-bit range
21300 * and the final length may be >= 2**32. However, we restrict the
21301 * final result to 32-bit range for practicality.
21302 */
21303
21304 if (len + (duk_uint32_t) nargs < len) {
21305 DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
21306 return DUK_RET_RANGE_ERROR;
21307 }
21308
21309 i = len;
21310 while (i > 0) {
21311 DUK_ASSERT_TOP(ctx, nargs + 2);
21312 i--;
21313 /* k+argCount-1; note that may be above 32-bit range */
21314
21315 if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) {
21316 /* fromPresent = true */
21317 /* [ ... ToObject(this) ToUint32(length) val ] */
21318 duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
21319 } else {
21320 /* fromPresent = false */
21321 /* [ ... ToObject(this) ToUint32(length) val ] */
21322 duk_pop(ctx);
21323 duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
21324 }
21325 DUK_ASSERT_TOP(ctx, nargs + 2);
21326 }
21327
21328 for (i = 0; i < (duk_uint32_t) nargs; i++) {
21329 DUK_ASSERT_TOP(ctx, nargs + 2);
21330 duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
21331 duk_put_prop_index(ctx, -3, (duk_uarridx_t) i);
21332 DUK_ASSERT_TOP(ctx, nargs + 2);
21333 }
21334
21335 DUK_ASSERT_TOP(ctx, nargs + 2);
21336 duk_push_u32(ctx, len + nargs);
21337 duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
21338 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
21339 return 1;
21340}
21341
21342/*
21343 * indexOf(), lastIndexOf()
21344 */
21345
21346DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
21347 duk_idx_t nargs;
21348 duk_int_t i, len;
21349 duk_int_t from_index;
21350 duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
21351
21352 /* lastIndexOf() needs to be a vararg function because we must distinguish
21353 * between an undefined fromIndex and a "not given" fromIndex; indexOf() is
21354 * made vararg for symmetry although it doesn't strictly need to be.
21355 */
21356
21357 nargs = duk_get_top(ctx);
21358 duk_set_top(ctx, 2);
21359
21360 /* XXX: must be able to represent -len */
21361 len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx);
21362 if (len == 0) {
21363 goto not_found;
21364 }
21365
21366 /* Index clamping is a bit tricky, we must ensure that we'll only iterate
21367 * through elements that exist and that the specific requirements from E5.1
21368 * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially:
21369 *
21370 * - indexOf: clamp to [-len,len], negative handling -> [0,len],
21371 * if clamped result is len, for-loop bails out immediately
21372 *
21373 * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1],
21374 * if clamped result is -1, for-loop bails out immediately
21375 *
21376 * If fromIndex is not given, ToInteger(undefined) = 0, which is correct
21377 * for indexOf() but incorrect for lastIndexOf(). Hence special handling,
21378 * and why lastIndexOf() needs to be a vararg function.
21379 */
21380
21381 if (nargs >= 2) {
21382 /* indexOf: clamp fromIndex to [-len, len]
21383 * (if fromIndex == len, for-loop terminates directly)
21384 *
21385 * lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
21386 * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
21387 */
21388 from_index = duk_to_int_clamped(ctx,
21389 1,
21390 (idx_step > 0 ? -len : -len - 1),
21391 (idx_step > 0 ? len : len - 1));
21392 if (from_index < 0) {
21393 /* for lastIndexOf, result may be -1 (mark immediate termination) */
21394 from_index = len + from_index;
21395 }
21396 } else {
21397 /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
21398 * handle both indexOf and lastIndexOf specially here.
21399 */
21400 if (idx_step > 0) {
21401 from_index = 0;
21402 } else {
21403 from_index = len - 1;
21404 }
21405 }
21406
21407 /* stack[0] = searchElement
21408 * stack[1] = fromIndex
21409 * stack[2] = object
21410 * stack[3] = length (not needed, but not popped above)
21411 */
21412
21413 for (i = from_index; i >= 0 && i < len; i += idx_step) {
21414 DUK_ASSERT_TOP(ctx, 4);
21415
21416 if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21417 DUK_ASSERT_TOP(ctx, 5);
21418 if (duk_strict_equals(ctx, 0, 4)) {
21419 duk_push_int(ctx, i);
21420 return 1;
21421 }
21422 }
21423
21424 duk_pop(ctx);
21425 }
21426
21427 not_found:
21428 duk_push_int(ctx, -1);
21429 return 1;
21430}
21431
21432/*
21433 * every(), some(), forEach(), map(), filter()
21434 */
21435
21436#define DUK__ITER_EVERY 0
21437#define DUK__ITER_SOME 1
21438#define DUK__ITER_FOREACH 2
21439#define DUK__ITER_MAP 3
21440#define DUK__ITER_FILTER 4
21441
21442/* XXX: This helper is a bit awkward because the handling for the different iteration
21443 * callers is quite different. This now compiles to a bit less than 500 bytes, so with
21444 * 5 callers the net result is about 100 bytes / caller.
21445 */
21446
21447DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
21448 duk_uint32_t len;
21449 duk_uint32_t i;
21450 duk_uarridx_t k;
21451 duk_bool_t bval;
21452 duk_small_int_t iter_type = duk_get_current_magic(ctx);
21453 duk_uint32_t res_length = 0;
21454
21455 /* each call this helper serves has nargs==2 */
21456 DUK_ASSERT_TOP(ctx, 2);
21457
21458 len = duk__push_this_obj_len_u32(ctx);
21459 duk_require_callable(ctx, 0);
21460 /* if thisArg not supplied, behave as if undefined was supplied */
21461
21462 if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
21463 duk_push_array(ctx);
21464 } else {
21465 duk_push_undefined(ctx);
21466 }
21467
21468 /* stack[0] = callback
21469 * stack[1] = thisArg
21470 * stack[2] = object
21471 * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop)
21472 * stack[4] = result array (or undefined)
21473 */
21474
21475 k = 0; /* result index for filter() */
21476 for (i = 0; i < len; i++) {
21477 DUK_ASSERT_TOP(ctx, 5);
21478
21479 if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21480#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
21481 /* Real world behavior for map(): trailing non-existent
21482 * elements don't invoke the user callback, but are still
21483 * counted towards result 'length'.
21484 */
21485 if (iter_type == DUK__ITER_MAP) {
21486 res_length = i + 1;
21487 }
21488#else
21489 /* Standard behavior for map(): trailing non-existent
21490 * elements don't invoke the user callback and are not
21491 * counted towards result 'length'.
21492 */
21493#endif
21494 duk_pop(ctx);
21495 continue;
21496 }
21497
21498 /* The original value needs to be preserved for filter(), hence
21499 * this funny order. We can't re-get the value because of side
21500 * effects.
21501 */
21502
21503 duk_dup(ctx, 0);
21504 duk_dup(ctx, 1);
21505 duk_dup(ctx, -3);
21506 duk_push_u32(ctx, i);
21507 duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */
21508 duk_call_method(ctx, 3); /* -> [ ... val retval ] */
21509
21510 switch (iter_type) {
21511 case DUK__ITER_EVERY:
21512 bval = duk_to_boolean(ctx, -1);
21513 if (!bval) {
21514 /* stack top contains 'false' */
21515 return 1;
21516 }
21517 break;
21518 case DUK__ITER_SOME:
21519 bval = duk_to_boolean(ctx, -1);
21520 if (bval) {
21521 /* stack top contains 'true' */
21522 return 1;
21523 }
21524 break;
21525 case DUK__ITER_FOREACH:
21526 /* nop */
21527 break;
21528 case DUK__ITER_MAP:
21529 duk_dup(ctx, -1);
21530 duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */
21531 res_length = i + 1;
21532 break;
21533 case DUK__ITER_FILTER:
21534 bval = duk_to_boolean(ctx, -1);
21535 if (bval) {
21536 duk_dup(ctx, -2); /* orig value */
21537 duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k);
21538 k++;
21539 res_length = k;
21540 }
21541 break;
21542 default:
21543 DUK_UNREACHABLE();
21544 break;
21545 }
21546 duk_pop_2(ctx);
21547
21548 DUK_ASSERT_TOP(ctx, 5);
21549 }
21550
21551 switch (iter_type) {
21552 case DUK__ITER_EVERY:
21553 duk_push_true(ctx);
21554 break;
21555 case DUK__ITER_SOME:
21556 duk_push_false(ctx);
21557 break;
21558 case DUK__ITER_FOREACH:
21559 duk_push_undefined(ctx);
21560 break;
21561 case DUK__ITER_MAP:
21562 case DUK__ITER_FILTER:
21563 DUK_ASSERT_TOP(ctx, 5);
21564 DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */
21565 duk_push_u32(ctx, res_length);
21566 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
21567 break;
21568 default:
21569 DUK_UNREACHABLE();
21570 break;
21571 }
21572
21573 return 1;
21574}
21575
21576/*
21577 * reduce(), reduceRight()
21578 */
21579
21580DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
21581 duk_idx_t nargs;
21582 duk_bool_t have_acc;
21583 duk_uint32_t i, len;
21584 duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */
21585
21586 /* We're a varargs function because we need to detect whether
21587 * initialValue was given or not.
21588 */
21589 nargs = duk_get_top(ctx);
21590 DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
21591
21592 duk_set_top(ctx, 2);
21593 len = duk__push_this_obj_len_u32(ctx);
21594 if (!duk_is_callable(ctx, 0)) {
21595 goto type_error;
21596 }
21597
21598 /* stack[0] = callback fn
21599 * stack[1] = initialValue
21600 * stack[2] = object (coerced this)
21601 * stack[3] = length (not needed, but not popped above)
21602 * stack[4] = accumulator
21603 */
21604
21605 have_acc = 0;
21606 if (nargs >= 2) {
21607 duk_dup(ctx, 1);
21608 have_acc = 1;
21609 }
21610 DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
21611 (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));
21612
21613 /* For len == 0, i is initialized to len - 1 which underflows.
21614 * The condition (i < len) will then exit the for-loop on the
21615 * first round which is correct. Similarly, loop termination
21616 * happens by i underflowing.
21617 */
21618
21619 for (i = (idx_step >= 0 ? 0 : len - 1);
21620 i < len; /* i >= 0 would always be true */
21621 i += idx_step) {
21622 DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
21623 (long) i, (long) len, (long) have_acc,
21624 (long) duk_get_top(ctx),
21625 (duk_tval *) duk_get_tval(ctx, 4)));
21626
21627 DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
21628 (!have_acc && duk_get_top(ctx) == 4));
21629
21630 if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21631 continue;
21632 }
21633
21634 if (!have_acc) {
21635 DUK_ASSERT_TOP(ctx, 4);
21636 duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
21637 have_acc = 1;
21638 DUK_ASSERT_TOP(ctx, 5);
21639 } else {
21640 DUK_ASSERT_TOP(ctx, 5);
21641 duk_dup(ctx, 0);
21642 duk_dup(ctx, 4);
21643 duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
21644 duk_push_u32(ctx, i);
21645 duk_dup(ctx, 2);
21646 DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
21647 (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
21648 (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
21649 (duk_tval *) duk_get_tval(ctx, -1)));
21650 duk_call(ctx, 4);
21651 DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
21652 duk_replace(ctx, 4);
21653 DUK_ASSERT_TOP(ctx, 5);
21654 }
21655 }
21656
21657 if (!have_acc) {
21658 goto type_error;
21659 }
21660
21661 DUK_ASSERT_TOP(ctx, 5);
21662 return 1;
21663
21664 type_error:
21665 return DUK_RET_TYPE_ERROR;
21666}
21667
21668#undef DUK__ARRAY_MID_JOIN_LIMIT
21669
21670#undef DUK__ITER_EVERY
21671#undef DUK__ITER_SOME
21672#undef DUK__ITER_FOREACH
21673#undef DUK__ITER_MAP
21674#undef DUK__ITER_FILTER
21675#line 1 "duk_bi_boolean.c"
21676/*
21677 * Boolean built-ins
21678 */
21679
21680/* include removed: duk_internal.h */
21681
21682/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
21683 * the primitive value to stack top, and optionally coerces with ToString().
21684 */
21685DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
21686 duk_tval *tv;
21687 duk_hobject *h;
21688 duk_small_int_t coerce_tostring = duk_get_current_magic(ctx);
21689
21690 /* XXX: there is room to use a shared helper here, many built-ins
21691 * check the 'this' type, and if it's an object, check its class,
21692 * then get its internal value, etc.
21693 */
21694
21695 duk_push_this(ctx);
21696 tv = duk_get_tval(ctx, -1);
21697 DUK_ASSERT(tv != NULL);
21698
21699 if (DUK_TVAL_IS_BOOLEAN(tv)) {
21700 goto type_ok;
21701 } else if (DUK_TVAL_IS_OBJECT(tv)) {
21702 h = DUK_TVAL_GET_OBJECT(tv);
21703 DUK_ASSERT(h != NULL);
21704
21705 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
21706 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
21707 DUK_ASSERT(duk_is_boolean(ctx, -1));
21708 goto type_ok;
21709 }
21710 }
21711
21712 return DUK_RET_TYPE_ERROR;
21713
21714 type_ok:
21715 if (coerce_tostring) {
21716 duk_to_string(ctx, -1);
21717 }
21718 return 1;
21719}
21720
21721DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) {
21722 duk_hthread *thr = (duk_hthread *) ctx;
21723 duk_hobject *h_this;
21724
21725 DUK_UNREF(thr);
21726
21727 duk_to_boolean(ctx, 0);
21728
21729 if (duk_is_constructor_call(ctx)) {
21730 /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
21731 duk_push_this(ctx);
21732 h_this = duk_get_hobject(ctx, -1);
21733 DUK_ASSERT(h_this != NULL);
21734 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
21735
21736 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
21737
21738 duk_dup(ctx, 0); /* -> [ val obj val ] */
21739 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
21740 } /* unbalanced stack */
21741
21742 return 1;
21743}
21744#line 1 "duk_bi_buffer.c"
21745/*
21746 * Duktape.Buffer, Node.js Buffer, and Khronos/ES6 TypedArray built-ins
21747 */
21748
21749/* include removed: duk_internal.h */
21750
21751/*
21752 * Misc helpers
21753 */
21754
21755#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21756/* Map DUK_HBUFFEROBJECT_ELEM_xxx to duk_hobject class number.
21757 * Sync with duk_hbufferobject.h and duk_hobject.h.
21758 */
21759static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
21760 DUK_HOBJECT_CLASS_UINT8ARRAY,
21761 DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY,
21762 DUK_HOBJECT_CLASS_INT8ARRAY,
21763 DUK_HOBJECT_CLASS_UINT16ARRAY,
21764 DUK_HOBJECT_CLASS_INT16ARRAY,
21765 DUK_HOBJECT_CLASS_UINT32ARRAY,
21766 DUK_HOBJECT_CLASS_INT32ARRAY,
21767 DUK_HOBJECT_CLASS_FLOAT32ARRAY,
21768 DUK_HOBJECT_CLASS_FLOAT64ARRAY
21769};
21770#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21771
21772#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21773/* Map DUK_HBUFFEROBJECT_ELEM_xxx to prototype object built-in index.
21774 * Sync with duk_hbufferobject.h.
21775 */
21776static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
21777 DUK_BIDX_UINT8ARRAY_PROTOTYPE,
21778 DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
21779 DUK_BIDX_INT8ARRAY_PROTOTYPE,
21780 DUK_BIDX_UINT16ARRAY_PROTOTYPE,
21781 DUK_BIDX_INT16ARRAY_PROTOTYPE,
21782 DUK_BIDX_UINT32ARRAY_PROTOTYPE,
21783 DUK_BIDX_INT32ARRAY_PROTOTYPE,
21784 DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
21785 DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
21786};
21787#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21788
21789#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21790/* Map DUK__FLX_xxx to byte size.
21791 */
21792static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
21793 1, /* DUK__FLD_8BIT */
21794 2, /* DUK__FLD_16BIT */
21795 4, /* DUK__FLD_32BIT */
21796 4, /* DUK__FLD_FLOAT */
21797 8, /* DUK__FLD_DOUBLE */
21798 0 /* DUK__FLD_VARINT; not relevant here */
21799};
21800#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21801
21802#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21803/* Bitfield for each DUK_HBUFFEROBJECT_ELEM_xxx indicating which element types
21804 * are compatible with a blind byte copy for the TypedArray set() method (also
21805 * used for TypedArray constructor). Array index is target buffer elem type,
21806 * bitfield indicates compatible source types. The types must have same byte
21807 * size and they must be coercion compatible.
21808 */
21809static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
21810 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8 */
21811 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
21812 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
21813 (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
21814
21815 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED
21816 * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
21817 */
21818 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
21819 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED),
21820
21821 /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT8 */
21822 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
21823 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
21824 (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
21825
21826 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT16 */
21827 (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
21828 (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
21829
21830 /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT16 */
21831 (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
21832 (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
21833
21834 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT32 */
21835 (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
21836 (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
21837
21838 /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT32 */
21839 (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
21840 (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
21841
21842 /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT32 */
21843 (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT32),
21844
21845 /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT64 */
21846 (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT64)
21847};
21848#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21849
21850#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21851/* Shared helper. */
21852DUK_LOCAL duk_hbufferobject *duk__getrequire_bufobj_this(duk_context *ctx, duk_bool_t throw_flag) {
21853 duk_hthread *thr;
21854 duk_tval *tv;
21855 duk_hbufferobject *h_this;
21856
21857 DUK_ASSERT(ctx != NULL);
21858 thr = (duk_hthread *) ctx;
21859
21860 tv = duk_get_borrowed_this_tval(ctx);
21861 DUK_ASSERT(tv != NULL);
21862 if (DUK_TVAL_IS_OBJECT(tv)) {
21863 h_this = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
21864 DUK_ASSERT(h_this != NULL);
21865 if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_this)) {
21866 DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
21867 return h_this;
21868 }
21869 }
21870
21871 if (throw_flag) {
21872 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
21873 }
21874 return NULL;
21875}
21876#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21877
21878#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21879/* Check that 'this' is a duk_hbufferobject and return a pointer to it. */
21880DUK_LOCAL duk_hbufferobject *duk__get_bufobj_this(duk_context *ctx) {
21881 return duk__getrequire_bufobj_this(ctx, 0);
21882}
21883#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21884
21885#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21886/* Check that 'this' is a duk_hbufferobject and return a pointer to it
21887 * (NULL if not).
21888 */
21889DUK_LOCAL duk_hbufferobject *duk__require_bufobj_this(duk_context *ctx) {
21890 return duk__getrequire_bufobj_this(ctx, 1);
21891}
21892#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21893
21894#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21895/* Check that value is a duk_hbufferobject and return a pointer to it. */
21896DUK_LOCAL duk_hbufferobject *duk__require_bufobj_value(duk_context *ctx, duk_idx_t index) {
21897 duk_hthread *thr;
21898 duk_tval *tv;
21899 duk_hbufferobject *h_obj;
21900
21901 thr = (duk_hthread *) ctx;
21902
21903 /* Don't accept relative indices now. */
21904 DUK_ASSERT(index >= 0);
21905
21906 tv = duk_require_tval(ctx, index);
21907 DUK_ASSERT(tv != NULL);
21908 if (DUK_TVAL_IS_OBJECT(tv)) {
21909 h_obj = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
21910 DUK_ASSERT(h_obj != NULL);
21911 if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_obj)) {
21912 DUK_ASSERT_HBUFFEROBJECT_VALID(h_obj);
21913 return h_obj;
21914 }
21915 }
21916
21917 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
21918 return NULL; /* not reachable */
21919}
21920#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21921
21922DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_hbuffer *h_val) {
21923 duk_hthread *thr;
21924
21925 thr = (duk_hthread *) ctx;
21926 DUK_UNREF(thr);
21927
21928 DUK_ASSERT(ctx != NULL);
21929 DUK_ASSERT(h_bufobj != NULL);
21930 DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
21931 DUK_ASSERT(h_val != NULL);
21932 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
21933
21934 h_bufobj->buf = h_val;
21935 DUK_HBUFFER_INCREF(thr, h_val);
21936 h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
21937 DUK_ASSERT(h_bufobj->shift == 0);
21938 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
21939
21940 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
21941}
21942
21943#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21944DUK_LOCAL duk_hbufferobject *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) {
21945 duk_hbuffer *h_val;
21946 duk_hbufferobject *h_bufobj;
21947
21948 (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
21949 h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
21950 DUK_ASSERT(h_val != NULL);
21951
21952 h_bufobj = duk_push_bufferobject_raw(ctx,
21953 DUK_HOBJECT_FLAG_EXTENSIBLE |
21954 DUK_HOBJECT_FLAG_BUFFEROBJECT |
21955 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
21956 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
21957 DUK_ASSERT(h_bufobj != NULL);
21958
21959 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
21960 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
21961
21962 return h_bufobj;
21963}
21964#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21965
21966#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21967/* Shared offset/length coercion helper. */
21968DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
21969 duk_hbufferobject *h_bufarg,
21970 duk_idx_t idx_offset,
21971 duk_idx_t idx_length,
21972 duk_uint_t *out_offset,
21973 duk_uint_t *out_length,
21974 duk_bool_t throw_flag) {
21975 duk_hthread *thr;
21976 duk_int_t offset_signed;
21977 duk_int_t length_signed;
21978 duk_uint_t offset;
21979 duk_uint_t length;
21980
21981 thr = (duk_hthread *) ctx;
21982 DUK_UNREF(thr);
21983
21984 offset_signed = duk_to_int(ctx, idx_offset);
21985 if (offset_signed < 0) {
21986 goto fail_range;
21987 }
21988 offset = (duk_uint_t) offset_signed;
21989 if (offset > h_bufarg->length) {
21990 goto fail_range;
21991 }
21992 DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
21993 DUK_ASSERT(offset <= h_bufarg->length);
21994
21995 if (duk_is_undefined(ctx, idx_length)) {
21996 DUK_ASSERT(h_bufarg->length >= offset);
21997 length = h_bufarg->length - offset; /* >= 0 */
21998 } else {
21999 length_signed = duk_to_int(ctx, idx_length);
22000 if (length_signed < 0) {
22001 goto fail_range;
22002 }
22003 length = (duk_uint_t) length_signed;
22004 DUK_ASSERT(h_bufarg->length >= offset);
22005 if (length > h_bufarg->length - offset) {
22006 /* Unlike for negative arguments, some call sites
22007 * want length to be clamped if it's positive.
22008 */
22009 if (throw_flag) {
22010 goto fail_range;
22011 } else {
22012 length = h_bufarg->length - offset;
22013 }
22014 }
22015 }
22016 DUK_ASSERT_DISABLE(length >= 0); /* unsigned */
22017 DUK_ASSERT(offset + length <= h_bufarg->length);
22018
22019 *out_offset = offset;
22020 *out_length = length;
22021 return;
22022
22023 fail_range:
22024 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
22025}
22026#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22027
22028#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22029/* Shared lenient buffer length clamping helper. No negative indices, no
22030 * element/byte shifting.
22031 */
22032DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
22033 duk_hbufferobject *h_bufobj,
22034 duk_idx_t idx_start,
22035 duk_idx_t idx_end,
22036 duk_int_t *out_start_offset,
22037 duk_int_t *out_end_offset) {
22038 duk_int_t buffer_length;
22039 duk_int_t start_offset;
22040 duk_int_t end_offset;
22041
22042 DUK_ASSERT(out_start_offset != NULL);
22043 DUK_ASSERT(out_end_offset != NULL);
22044
22045 buffer_length = (duk_int_t) h_bufobj->length;
22046
22047 /* undefined coerces to zero which is correct */
22048 start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length);
22049 if (duk_is_undefined(ctx, idx_end)) {
22050 end_offset = buffer_length;
22051 } else {
22052 end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length);
22053 }
22054
22055 DUK_ASSERT(start_offset >= 0);
22056 DUK_ASSERT(start_offset <= buffer_length);
22057 DUK_ASSERT(end_offset >= 0);
22058 DUK_ASSERT(end_offset <= buffer_length);
22059 DUK_ASSERT(start_offset <= end_offset);
22060
22061 *out_start_offset = start_offset;
22062 *out_end_offset = end_offset;
22063}
22064#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22065
22066#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22067/* Shared lenient buffer length clamping helper. Indices are treated as
22068 * element indices (though output values are byte offsets) which only
22069 * really matters for TypedArray views as other buffer object have a zero
22070 * shift. Negative indices are counted from end of input slice; crossed
22071 * indices are clamped to zero length; and final indices are clamped
22072 * against input slice. Used for e.g. ArrayBuffer slice().
22073 */
22074DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
22075 duk_hbufferobject *h_bufobj,
22076 duk_idx_t idx_start,
22077 duk_idx_t idx_end,
22078 duk_int_t *out_start_offset,
22079 duk_int_t *out_end_offset) {
22080 duk_int_t buffer_length;
22081 duk_int_t start_offset;
22082 duk_int_t end_offset;
22083
22084 DUK_ASSERT(out_start_offset != NULL);
22085 DUK_ASSERT(out_end_offset != NULL);
22086
22087 buffer_length = (duk_int_t) h_bufobj->length;
22088 buffer_length >>= h_bufobj->shift; /* as elements */
22089
22090 /* Resolve start/end offset as element indices first; arguments
22091 * at idx_start/idx_end are element offsets. Working with element
22092 * indices first also avoids potential for wrapping.
22093 */
22094
22095 start_offset = duk_to_int(ctx, idx_start);
22096 if (start_offset < 0) {
22097 start_offset = buffer_length + start_offset;
22098 }
22099 if (duk_is_undefined(ctx, idx_end)) {
22100 end_offset = buffer_length;
22101 } else {
22102 end_offset = duk_to_int(ctx, idx_end);
22103 if (end_offset < 0) {
22104 end_offset = buffer_length + end_offset;
22105 }
22106 }
22107 /* Note: start_offset/end_offset can still be < 0 here. */
22108
22109 if (start_offset < 0) {
22110 start_offset = 0;
22111 } else if (start_offset > buffer_length) {
22112 start_offset = buffer_length;
22113 }
22114 if (end_offset < start_offset) {
22115 end_offset = start_offset;
22116 } else if (end_offset > buffer_length) {
22117 end_offset = buffer_length;
22118 }
22119 DUK_ASSERT(start_offset >= 0);
22120 DUK_ASSERT(start_offset <= buffer_length);
22121 DUK_ASSERT(end_offset >= 0);
22122 DUK_ASSERT(end_offset <= buffer_length);
22123 DUK_ASSERT(start_offset <= end_offset);
22124
22125 /* Convert indices to byte offsets. */
22126 start_offset <<= h_bufobj->shift;
22127 end_offset <<= h_bufobj->shift;
22128
22129 *out_start_offset = start_offset;
22130 *out_end_offset = end_offset;
22131}
22132#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22133
22134/*
22135 * Indexed read/write helpers (also used from outside this file)
22136 */
22137
22138DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
22139 duk_double_union du;
22140
22141 DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
22142
22143 switch (h_bufobj->elem_type) {
22144 case DUK_HBUFFEROBJECT_ELEM_UINT8:
22145#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22146 case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
22147#endif
22148 duk_push_uint(ctx, (duk_uint_t) du.uc[0]);
22149 break;
22150#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22151 /* These are not needed when only Duktape.Buffer is supported. */
22152 case DUK_HBUFFEROBJECT_ELEM_INT8:
22153 duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]);
22154 break;
22155 case DUK_HBUFFEROBJECT_ELEM_UINT16:
22156 duk_push_uint(ctx, (duk_uint_t) du.us[0]);
22157 break;
22158 case DUK_HBUFFEROBJECT_ELEM_INT16:
22159 duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]);
22160 break;
22161 case DUK_HBUFFEROBJECT_ELEM_UINT32:
22162 duk_push_uint(ctx, (duk_uint_t) du.ui[0]);
22163 break;
22164 case DUK_HBUFFEROBJECT_ELEM_INT32:
22165 duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]);
22166 break;
22167 case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
22168 duk_push_number(ctx, (duk_double_t) du.f[0]);
22169 break;
22170 case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
22171 duk_push_number(ctx, (duk_double_t) du.d);
22172 break;
22173#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22174 default:
22175 DUK_UNREACHABLE();
22176 }
22177}
22178
22179DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
22180 duk_double_union du;
22181
22182 /* NOTE! Caller must ensure that any side effects from the
22183 * coercions below are safe. If that cannot be guaranteed
22184 * (which is normally the case), caller must coerce the
22185 * argument using duk_to_number() before any pointer
22186 * validations; the result of duk_to_number() always coerces
22187 * without side effects here.
22188 */
22189
22190 switch (h_bufobj->elem_type) {
22191 case DUK_HBUFFEROBJECT_ELEM_UINT8:
22192 du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1);
22193 break;
22194#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22195 /* These are not needed when only Duktape.Buffer is supported. */
22196 case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
22197 du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1);
22198 break;
22199 case DUK_HBUFFEROBJECT_ELEM_INT8:
22200 du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1);
22201 break;
22202 case DUK_HBUFFEROBJECT_ELEM_UINT16:
22203 du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1);
22204 break;
22205 case DUK_HBUFFEROBJECT_ELEM_INT16:
22206 du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1);
22207 break;
22208 case DUK_HBUFFEROBJECT_ELEM_UINT32:
22209 du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1);
22210 break;
22211 case DUK_HBUFFEROBJECT_ELEM_INT32:
22212 du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1);
22213 break;
22214 case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
22215 du.f[0] = (duk_float_t) duk_to_number(ctx, -1);
22216 break;
22217 case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
22218 du.d = (duk_double_t) duk_to_number(ctx, -1);
22219 break;
22220#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22221 default:
22222 DUK_UNREACHABLE();
22223 }
22224
22225 DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
22226}
22227
22228/*
22229 * Duktape.Buffer: constructor
22230 */
22231
22232DUK_INTERNAL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx) {
22233 duk_hthread *thr;
22234 duk_size_t buf_size;
22235 duk_small_int_t buf_dynamic;
22236 duk_uint8_t *buf_data;
22237 const duk_uint8_t *src_data;
22238
22239 thr = (duk_hthread *) ctx;
22240 DUK_UNREF(thr);
22241
22242 /*
22243 * Constructor arguments are currently somewhat compatible with
22244 * (keep it that way if possible):
22245 *
22246 * http://nodejs.org/api/buffer.html
22247 *
22248 * Note that the ToBuffer() coercion (duk_to_buffer()) does NOT match
22249 * the constructor behavior.
22250 */
22251
22252 buf_dynamic = duk_get_boolean(ctx, 1); /* default to false */
22253
22254 switch (duk_get_type(ctx, 0)) {
22255 case DUK_TYPE_NUMBER: {
22256 /* new buffer of specified size */
22257 buf_size = (duk_size_t) duk_to_int(ctx, 0);
22258 (void) duk_push_buffer(ctx, buf_size, buf_dynamic);
22259 break;
22260 }
22261 case DUK_TYPE_BUFFER: {
22262 /* return input buffer, converted to a Duktape.Buffer object
22263 * if called as a constructor (no change if called as a
22264 * function).
22265 */
22266 duk_set_top(ctx, 1);
22267 break;
22268 }
22269 case DUK_TYPE_STRING: {
22270 /* new buffer with string contents */
22271 src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size);
22272 DUK_ASSERT(src_data != NULL); /* even for zero-length string */
22273 buf_data = (duk_uint8_t *) duk_push_buffer(ctx, buf_size, buf_dynamic);
22274 DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size);
22275 break;
22276 }
22277 case DUK_TYPE_OBJECT: {
22278 /* For all duk_hbufferobjects, get the plain buffer inside
22279 * without making a copy. This is compatible with Duktape 1.2
22280 * but means that a slice/view information is ignored and the
22281 * full underlying buffer is returned.
22282 *
22283 * If called as a constructor, a new Duktape.Buffer object
22284 * pointing to the same plain buffer is created below.
22285 */
22286 duk_hbufferobject *h_bufobj;
22287 h_bufobj = (duk_hbufferobject *) duk_get_hobject(ctx, 0);
22288 DUK_ASSERT(h_bufobj != NULL);
22289 if (!DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)) {
22290 return DUK_RET_TYPE_ERROR;
22291 }
22292 if (h_bufobj->buf == NULL) {
22293 return DUK_RET_TYPE_ERROR;
22294 }
22295 duk_push_hbuffer(ctx, h_bufobj->buf);
22296 break;
22297 }
22298 case DUK_TYPE_NONE:
22299 default: {
22300 return DUK_RET_TYPE_ERROR;
22301 }
22302 }
22303 DUK_ASSERT(duk_is_buffer(ctx, -1));
22304
22305 /* stack is unbalanced, but: [ <something> buf ] */
22306
22307 if (duk_is_constructor_call(ctx)) {
22308 duk_hbufferobject *h_bufobj;
22309 duk_hbuffer *h_val;
22310
22311 h_val = duk_get_hbuffer(ctx, -1);
22312 DUK_ASSERT(h_val != NULL);
22313
22314 h_bufobj = duk_push_bufferobject_raw(ctx,
22315 DUK_HOBJECT_FLAG_EXTENSIBLE |
22316 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22317 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
22318 DUK_BIDX_BUFFER_PROTOTYPE);
22319 DUK_ASSERT(h_bufobj != NULL);
22320
22321 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
22322
22323 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22324 }
22325 /* Note: unbalanced stack on purpose */
22326
22327 return 1;
22328}
22329
22330/*
22331 * Node.js Buffer: constructor
22332 */
22333
22334#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22335DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
22336 /* Internal class is Object: Object.prototype.toString.call(new Buffer(0))
22337 * prints "[object Object]".
22338 */
22339 duk_int_t len;
22340 duk_int_t i;
22341 duk_hbuffer *h_buf;
22342 duk_hbufferobject *h_bufobj;
22343 duk_size_t buf_size;
22344
22345 switch (duk_get_type(ctx, 0)) {
22346 case DUK_TYPE_BUFFER: {
22347 /* Custom behavior: plain buffer is used as internal buffer
22348 * without making a copy (matches Duktape.Buffer).
22349 */
22350 duk_set_top(ctx, 1); /* -> [ buffer ] */
22351 break;
22352 }
22353 case DUK_TYPE_NUMBER: {
22354 len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX);
22355 (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
22356 break;
22357 }
22358 case DUK_TYPE_OBJECT: {
22359 duk_uint8_t *buf;
22360
22361 (void) duk_get_prop_string(ctx, 0, "length");
22362 len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX);
22363 duk_pop(ctx);
22364 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
22365 for (i = 0; i < len; i++) {
22366 /* XXX: fast path for array arguments? */
22367 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
22368 buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU);
22369 duk_pop(ctx);
22370 }
22371 break;
22372 }
22373 case DUK_TYPE_STRING: {
22374 /* ignore encoding for now */
22375 duk_dup(ctx, 0);
22376 (void) duk_to_buffer(ctx, -1, &buf_size);
22377 break;
22378 }
22379 default:
22380 return DUK_RET_TYPE_ERROR;
22381 }
22382
22383 DUK_ASSERT(duk_is_buffer(ctx, -1));
22384 h_buf = duk_get_hbuffer(ctx, -1);
22385 DUK_ASSERT(h_buf != NULL);
22386
22387 h_bufobj = duk_push_bufferobject_raw(ctx,
22388 DUK_HOBJECT_FLAG_EXTENSIBLE |
22389 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22390 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
22391 DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
22392 DUK_ASSERT(h_bufobj != NULL);
22393
22394 h_bufobj->buf = h_buf;
22395 DUK_HBUFFER_INCREF(thr, h_buf);
22396 DUK_ASSERT(h_bufobj->offset == 0);
22397 h_bufobj->length = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_buf);
22398 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
22399
22400 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22401
22402 return 1;
22403}
22404#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22405DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
22406 DUK_UNREF(ctx);
22407 return DUK_RET_UNSUPPORTED_ERROR;
22408}
22409#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22410
22411/*
22412 * ArrayBuffer, DataView, and TypedArray constructors
22413 */
22414
22415#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22416DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
22417 duk_hthread *thr;
22418 duk_hbufferobject *h_bufobj;
22419 duk_hbuffer *h_val;
22420
22421 DUK_ASSERT_CTX_VALID(ctx);
22422 thr = (duk_hthread *) ctx;
22423 DUK_UNREF(thr);
22424
22425 /* XXX: function flag to make this automatic? */
22426 if (!duk_is_constructor_call(ctx)) {
22427 return DUK_RET_TYPE_ERROR;
22428 }
22429
22430 if (duk_is_buffer(ctx, 0)) {
22431 /* Custom behavior: plain buffer is used as internal buffer
22432 * without making a copy (matches Duktape.Buffer).
22433 */
22434
22435 h_val = duk_get_hbuffer(ctx, 0);
22436 DUK_ASSERT(h_val != NULL);
22437
22438 /* XXX: accept any duk_hbufferobject type as an input also? */
22439 } else {
22440 duk_int_t len;
22441 len = duk_to_int(ctx, 0);
22442 if (len < 0) {
22443 goto fail_length;
22444 }
22445 (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
22446 h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
22447 DUK_ASSERT(h_val != NULL);
22448
22449#if !defined(DUK_USE_ZERO_BUFFER_DATA)
22450 /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
22451 * is not set.
22452 */
22453 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
22454 DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len);
22455#endif
22456 }
22457
22458 h_bufobj = duk_push_bufferobject_raw(ctx,
22459 DUK_HOBJECT_FLAG_EXTENSIBLE |
22460 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22461 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
22462 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
22463 DUK_ASSERT(h_bufobj != NULL);
22464
22465 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
22466 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22467
22468 return 1;
22469
22470 fail_length:
22471 return DUK_RET_RANGE_ERROR;
22472}
22473#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22474DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
22475 DUK_UNREF(ctx);
22476 return DUK_RET_UNSUPPORTED_ERROR;
22477}
22478#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22479
22480
22481/* Format of magic, bits:
22482 * 0...1: elem size shift (0-3)
22483 * 2...5: elem type (DUK_HBUFFEROBJECT_ELEM_xxx)
22484 */
22485
22486#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22487DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
22488 duk_hthread *thr;
22489 duk_tval *tv;
22490 duk_hobject *h_obj;
22491 duk_hbufferobject *h_bufobj = NULL;
22492 duk_hbufferobject *h_bufarr = NULL;
22493 duk_hbufferobject *h_bufarg = NULL;
22494 duk_hbuffer *h_val;
22495 duk_small_uint_t magic;
22496 duk_small_uint_t shift;
22497 duk_small_uint_t elem_type;
22498 duk_small_uint_t elem_size;
22499 duk_small_uint_t class_num;
22500 duk_small_uint_t proto_bidx;
22501 duk_uint_t align_mask;
22502 duk_uint_t elem_length;
22503 duk_int_t elem_length_signed;
22504 duk_uint_t byte_length;
22505 duk_small_uint_t copy_mode;
22506
22507 thr = (duk_hthread *) ctx;
22508 DUK_UNREF(thr);
22509
22510 /* XXX: function flag to make this automatic? */
22511 if (!duk_is_constructor_call(ctx)) {
22512 return DUK_RET_TYPE_ERROR;
22513 }
22514
22515 /* We could fit built-in index into magic but that'd make the magic
22516 * number dependent on built-in numbering (genbuiltins.py doesn't
22517 * handle that yet). So map both class and prototype from the
22518 * element type.
22519 */
22520 magic = duk_get_current_magic(ctx);
22521 shift = magic & 0x03; /* bits 0...1: shift */
22522 elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */
22523 elem_size = 1 << shift;
22524 align_mask = elem_size - 1;
22525 DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
22526 proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
22527 DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS);
22528 DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t));
22529 class_num = duk__buffer_class_from_elemtype[elem_type];
22530
22531 DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, "
22532 "elem_size=%d, proto_bidx=%d, class_num=%d",
22533 (int) magic, (int) shift, (int) elem_type, (int) elem_size,
22534 (int) proto_bidx, (int) class_num));
22535
22536 /* Argument variants. When the argument is an ArrayBuffer a view to
22537 * the same buffer is created; otherwise a new ArrayBuffer is always
22538 * created.
22539 */
22540
22541 tv = duk_get_tval(ctx, 0);
22542 DUK_ASSERT(tv != NULL); /* arg count */
22543 if (DUK_TVAL_IS_OBJECT(tv)) {
22544 h_obj = DUK_TVAL_GET_OBJECT(tv);
22545 DUK_ASSERT(h_obj != NULL);
22546
22547 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
22548 /* ArrayBuffer: unlike any other argument variant, create
22549 * a view into the existing buffer.
22550 */
22551
22552 duk_int_t byte_offset_signed;
22553 duk_uint_t byte_offset;
22554
22555 h_bufarg = (duk_hbufferobject *) h_obj;
22556
22557 byte_offset_signed = duk_to_int(ctx, 1);
22558 if (byte_offset_signed < 0) {
22559 goto fail_arguments;
22560 }
22561 byte_offset = (duk_uint_t) byte_offset_signed;
22562 if (byte_offset > h_bufarg->length ||
22563 (byte_offset & align_mask) != 0) {
22564 /* Must be >= 0 and multiple of element size. */
22565 goto fail_arguments;
22566 }
22567 if (duk_is_undefined(ctx, 2)) {
22568 DUK_ASSERT(h_bufarg->length >= byte_offset);
22569 byte_length = h_bufarg->length - byte_offset;
22570 if ((byte_length & align_mask) != 0) {
22571 /* Must be element size multiple from
22572 * start offset to end of buffer.
22573 */
22574 goto fail_arguments;
22575 }
22576 elem_length = (byte_length >> shift);
22577 } else {
22578 elem_length_signed = duk_to_int(ctx, 2);
22579 if (elem_length_signed < 0) {
22580 goto fail_arguments;
22581 }
22582 elem_length = (duk_uint_t) elem_length_signed;
22583 byte_length = elem_length << shift;
22584 if ((byte_length >> shift) != elem_length) {
22585 /* Byte length would overflow. */
22586 /* XXX: easier check with less code? */
22587 goto fail_arguments;
22588 }
22589 DUK_ASSERT(h_bufarg->length >= byte_offset);
22590 if (byte_length > h_bufarg->length - byte_offset) {
22591 /* Not enough data. */
22592 goto fail_arguments;
22593 }
22594 }
22595 DUK_UNREF(elem_length);
22596 DUK_ASSERT_DISABLE(byte_offset >= 0);
22597 DUK_ASSERT(byte_offset <= h_bufarg->length);
22598 DUK_ASSERT_DISABLE(byte_length >= 0);
22599 DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
22600 DUK_ASSERT((elem_length << shift) == byte_length);
22601
22602 h_bufobj = duk_push_bufferobject_raw(ctx,
22603 DUK_HOBJECT_FLAG_EXTENSIBLE |
22604 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22605 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
22606 proto_bidx);
22607 h_val = h_bufarg->buf;
22608 if (h_val == NULL) {
22609 return DUK_RET_TYPE_ERROR;
22610 }
22611 h_bufobj->buf = h_val;
22612 DUK_HBUFFER_INCREF(thr, h_val);
22613 h_bufobj->offset = h_bufarg->offset + byte_offset;
22614 h_bufobj->length = byte_length;
22615 h_bufobj->shift = (duk_uint8_t) shift;
22616 h_bufobj->elem_type = (duk_uint8_t) elem_type;
22617 h_bufobj->is_view = 1;
22618 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22619
22620 /* Set .buffer to the argument ArrayBuffer. */
22621 duk_dup(ctx, 0);
22622 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
22623 duk_compact(ctx, -1);
22624 return 1;
22625 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
22626 /* TypedArray (or other non-ArrayBuffer duk_hbufferobject).
22627 * Conceptually same behavior as for an Array-like argument,
22628 * with a few fast paths.
22629 */
22630
22631 h_bufarg = (duk_hbufferobject *) h_obj;
22632 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
22633 elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
22634 if (h_bufarg->buf == NULL) {
22635 return DUK_RET_TYPE_ERROR;
22636 }
22637
22638 /* Select copy mode. Must take into account element
22639 * compatibility and validity of the underlying source
22640 * buffer.
22641 */
22642
22643 DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, "
22644 "src byte_length=%ld, src shift=%d, "
22645 "src/dst elem_length=%ld; "
22646 "dst shift=%d -> dst byte_length=%ld",
22647 (long) h_bufarg->length, (int) h_bufarg->shift,
22648 (long) elem_length_signed, (int) shift,
22649 (long) (elem_length_signed << shift)));
22650
22651 copy_mode = 2; /* default is explicit index read/write copy */
22652 DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
22653 if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
22654 if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
22655 DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
22656 DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */
22657 copy_mode = 0;
22658 } else {
22659 DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy"));
22660 copy_mode = 1;
22661 }
22662 }
22663 } else {
22664 /* Array or Array-like */
22665 elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
22666 copy_mode = 2;
22667 }
22668 } else if (DUK_TVAL_IS_BUFFER(tv)) {
22669 /* Accept plain buffer values like array initializers
22670 * (new in Duktape 1.4.0).
22671 */
22672 duk_hbuffer *h_srcbuf;
22673 h_srcbuf = DUK_TVAL_GET_BUFFER(tv);
22674 elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf);
22675 copy_mode = 2; /* XXX: could add fast path for u8 compatible views */
22676 } else {
22677 /* Non-object argument is simply int coerced, matches
22678 * V8 behavior (except for "null", which we coerce to
22679 * 0 but V8 TypeErrors).
22680 */
22681 elem_length_signed = duk_to_int(ctx, 0);
22682 copy_mode = 3;
22683 }
22684 if (elem_length_signed < 0) {
22685 goto fail_arguments;
22686 }
22687 elem_length = (duk_uint_t) elem_length_signed;
22688 byte_length = (duk_uint_t) (elem_length << shift);
22689 if ((byte_length >> shift) != elem_length) {
22690 /* Byte length would overflow. */
22691 /* XXX: easier check with less code? */
22692 goto fail_arguments;
22693 }
22694
22695 DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld",
22696 (long) elem_length, (long) byte_length));
22697
22698 /* ArrayBuffer argument is handled specially above; the rest of the
22699 * argument variants are handled by shared code below.
22700 */
22701
22702 /* Push a new ArrayBuffer (becomes view .buffer) */
22703 h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length);
22704 DUK_ASSERT(h_bufarr != NULL);
22705 h_val = h_bufarr->buf;
22706 DUK_ASSERT(h_val != NULL);
22707
22708 /* Push the resulting view object and attach the ArrayBuffer. */
22709 h_bufobj = duk_push_bufferobject_raw(ctx,
22710 DUK_HOBJECT_FLAG_EXTENSIBLE |
22711 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22712 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
22713 proto_bidx);
22714
22715 h_bufobj->buf = h_val;
22716 DUK_HBUFFER_INCREF(thr, h_val);
22717 DUK_ASSERT(h_bufobj->offset == 0);
22718 h_bufobj->length = byte_length;
22719 h_bufobj->shift = (duk_uint8_t) shift;
22720 h_bufobj->elem_type = (duk_uint8_t) elem_type;
22721 h_bufobj->is_view = 1;
22722 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22723
22724 /* Set .buffer */
22725 duk_dup(ctx, -2);
22726 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
22727 duk_compact(ctx, -1);
22728
22729 /* Copy values, the copy method depends on the arguments.
22730 *
22731 * Copy mode decision may depend on the validity of the underlying
22732 * buffer of the source argument; there must be no harmful side effects
22733 * from there to here for copy_mode to still be valid.
22734 */
22735 DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
22736 switch (copy_mode) {
22737 case 0: {
22738 /* Use byte copy. */
22739
22740 duk_uint8_t *p_src;
22741 duk_uint8_t *p_dst;
22742
22743 DUK_ASSERT(h_bufobj != NULL);
22744 DUK_ASSERT(h_bufobj->buf != NULL);
22745 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
22746 DUK_ASSERT(h_bufarg != NULL);
22747 DUK_ASSERT(h_bufarg->buf != NULL);
22748 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
22749
22750 p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
22751 p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
22752
22753 DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
22754 (void *) p_src, (void *) p_dst, (long) byte_length));
22755
22756 DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length);
22757 break;
22758 }
22759 case 1: {
22760 /* Copy values through direct validated reads and writes. */
22761
22762 duk_small_uint_t src_elem_size;
22763 duk_small_uint_t dst_elem_size;
22764 duk_uint8_t *p_src;
22765 duk_uint8_t *p_src_end;
22766 duk_uint8_t *p_dst;
22767
22768 DUK_ASSERT(h_bufobj != NULL);
22769 DUK_ASSERT(h_bufobj->buf != NULL);
22770 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
22771 DUK_ASSERT(h_bufarg != NULL);
22772 DUK_ASSERT(h_bufarg->buf != NULL);
22773 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
22774
22775 src_elem_size = 1 << h_bufarg->shift;
22776 dst_elem_size = elem_size;
22777
22778 p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
22779 p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
22780 p_src_end = p_src + h_bufarg->length;
22781
22782 DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
22783 "src_elem_size=%d, dst_elem_size=%d",
22784 (void *) p_src, (void *) p_src_end, (void *) p_dst,
22785 (int) src_elem_size, (int) dst_elem_size));
22786
22787 while (p_src != p_src_end) {
22788 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
22789 "p_src=%p, p_src_end=%p, p_dst=%p",
22790 (void *) p_src, (void *) p_src_end, (void *) p_dst));
22791 /* A validated read() is always a number, so it's write coercion
22792 * is always side effect free an won't invalidate pointers etc.
22793 */
22794 duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
22795 duk_hbufferobject_validated_write(ctx, h_bufobj, p_dst, dst_elem_size);
22796 duk_pop(ctx);
22797 p_src += src_elem_size;
22798 p_dst += dst_elem_size;
22799 }
22800 break;
22801 }
22802 case 2: {
22803 /* Copy values by index reads and writes. Let virtual
22804 * property handling take care of coercion.
22805 */
22806 duk_uint_t i;
22807
22808 DUK_DDD(DUK_DDDPRINT("using slow copy"));
22809
22810 for (i = 0; i < elem_length; i++) {
22811 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
22812 duk_put_prop_index(ctx, -2, (duk_uarridx_t) i);
22813 }
22814 break;
22815 }
22816 default:
22817 case 3: {
22818 /* No copy, leave zero bytes in the buffer. There's no
22819 * ambiguity with Float32/Float64 because zero bytes also
22820 * represent 0.0.
22821 */
22822#if !defined(DUK_USE_ZERO_BUFFER_DATA)
22823 /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
22824 * is not set.
22825 */
22826 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
22827 DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length);
22828#endif
22829
22830 DUK_DDD(DUK_DDDPRINT("using no copy"));
22831 break;
22832 }
22833 }
22834
22835 return 1;
22836
22837 fail_arguments:
22838 return DUK_RET_RANGE_ERROR;
22839}
22840#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22841DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
22842 DUK_UNREF(ctx);
22843 return DUK_RET_UNSUPPORTED_ERROR;
22844}
22845#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22846
22847#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22848DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
22849 duk_hbufferobject *h_bufarg;
22850 duk_hbufferobject *h_bufobj;
22851 duk_hbuffer *h_val;
22852 duk_uint_t offset;
22853 duk_uint_t length;
22854
22855 /* XXX: function flag to make this automatic? */
22856 if (!duk_is_constructor_call(ctx)) {
22857 return DUK_RET_TYPE_ERROR;
22858 }
22859
22860 h_bufarg = duk__require_bufobj_value(ctx, 0);
22861 DUK_ASSERT(h_bufarg != NULL);
22862
22863 duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
22864 DUK_ASSERT(offset <= h_bufarg->length);
22865 DUK_ASSERT(offset + length <= h_bufarg->length);
22866
22867 h_bufobj = duk_push_bufferobject_raw(ctx,
22868 DUK_HOBJECT_FLAG_EXTENSIBLE |
22869 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22870 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
22871 DUK_BIDX_DATAVIEW_PROTOTYPE);
22872
22873 h_val = h_bufarg->buf;
22874 if (h_val == NULL) {
22875 return DUK_RET_TYPE_ERROR;
22876 }
22877 h_bufobj->buf = h_val;
22878 DUK_HBUFFER_INCREF(thr, h_val);
22879 h_bufobj->offset = h_bufarg->offset + offset;
22880 h_bufobj->length = length;
22881 DUK_ASSERT(h_bufobj->shift == 0);
22882 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
22883 h_bufobj->is_view = 1;
22884
22885 /* The DataView .buffer property is ordinarily set to the argument
22886 * which is an ArrayBuffer. We accept any duk_hbufferobject as
22887 * an argument and .buffer will be set to the argument regardless
22888 * of what it is. This may be a bit confusing if the argument
22889 * is e.g. a DataView or another TypedArray view.
22890 *
22891 * XXX: Copy .buffer property from a DataView/TypedArray argument?
22892 * Create a fresh ArrayBuffer for Duktape.Buffer and Node.js Buffer
22893 * arguments? See: test-bug-dataview-buffer-prop.js.
22894 */
22895
22896 duk_dup(ctx, 0);
22897 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
22898 duk_compact(ctx, -1);
22899
22900 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22901 return 1;
22902}
22903#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22904DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
22905 DUK_UNREF(ctx);
22906 return DUK_RET_UNSUPPORTED_ERROR;
22907}
22908#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22909
22910/*
22911 * ArrayBuffer.isView()
22912 */
22913
22914#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22915DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
22916 duk_hobject *h_obj;
22917 duk_bool_t ret = 0;
22918
22919 h_obj = duk_get_hobject(ctx, 0);
22920 if (h_obj != NULL && DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
22921 ret = ((duk_hbufferobject *) h_obj)->is_view;
22922 }
22923 duk_push_boolean(ctx, ret);
22924 return 1;
22925}
22926#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22927DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
22928 DUK_UNREF(ctx);
22929 return DUK_RET_UNSUPPORTED_ERROR;
22930}
22931#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22932
22933/*
22934 * Node.js Buffer: toString([encoding], [start], [end])
22935 */
22936
22937#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22938DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
22939 duk_hthread *thr;
22940 duk_hbufferobject *h_this;
22941 duk_int_t start_offset, end_offset;
22942 duk_uint8_t *buf_slice;
22943 duk_size_t slice_length;
22944
22945 thr = (duk_hthread *) ctx;
22946 DUK_UNREF(thr);
22947
22948 h_this = duk__get_bufobj_this(ctx);
22949 if (h_this == NULL) {
22950 /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
22951 duk_push_string(ctx, "[object Object]");
22952 return 1;
22953 }
22954 DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
22955
22956 /* ignore encoding for now */
22957
22958 duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &start_offset, &end_offset);
22959
22960 slice_length = (duk_size_t) (end_offset - start_offset);
22961 buf_slice = (duk_uint8_t *) duk_push_fixed_buffer(ctx, slice_length);
22962 DUK_ASSERT(buf_slice != NULL);
22963
22964 if (h_this->buf == NULL) {
22965 goto type_error;
22966 }
22967
22968 if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
22969 DUK_MEMCPY((void *) buf_slice,
22970 (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
22971 (size_t) slice_length);
22972 } else {
22973 /* not covered, return all zeroes */
22974 ;
22975 }
22976
22977 duk_to_string(ctx, -1);
22978 return 1;
22979
22980 type_error:
22981 return DUK_RET_TYPE_ERROR;
22982}
22983#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22984DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
22985 DUK_UNREF(ctx);
22986 return DUK_RET_UNSUPPORTED_ERROR;
22987}
22988#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22989
22990/*
22991 * Duktape.Buffer: toString(), valueOf()
22992 */
22993
22994#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22995DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
22996 duk_hthread *thr;
22997 duk_tval *tv;
22998 duk_small_int_t to_string = duk_get_current_magic(ctx);
22999
23000 thr = (duk_hthread *) ctx;
23001 DUK_UNREF(thr);
23002
23003 tv = duk_get_borrowed_this_tval(ctx);
23004 DUK_ASSERT(tv != NULL);
23005
23006 if (DUK_TVAL_IS_BUFFER(tv)) {
23007 duk_hbuffer *h_buf;
23008 h_buf = DUK_TVAL_GET_BUFFER(tv);
23009 DUK_ASSERT(h_buf != NULL);
23010 duk_push_hbuffer(ctx, h_buf);
23011 } else if (DUK_TVAL_IS_OBJECT(tv)) {
23012 duk_hobject *h;
23013 duk_hbufferobject *h_bufobj;
23014
23015 /* Accept any duk_hbufferobject, though we're only normally
23016 * called for Duktape.Buffer values.
23017 */
23018 h = DUK_TVAL_GET_OBJECT(tv);
23019 DUK_ASSERT(h != NULL);
23020 if (!DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
23021 DUK_DD(DUK_DDPRINT("toString/valueOf() called for a non-bufferobject object"));
23022 goto type_error;
23023 }
23024 h_bufobj = (duk_hbufferobject *) h;
23025 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
23026
23027 if (h_bufobj->buf == NULL) {
23028 DUK_DD(DUK_DDPRINT("toString/valueOf() called for a bufferobject with NULL buf"));
23029 goto type_error;
23030 }
23031 duk_push_hbuffer(ctx, h_bufobj->buf);
23032 } else {
23033 goto type_error;
23034 }
23035
23036 if (to_string) {
23037 duk_to_string(ctx, -1);
23038 }
23039 return 1;
23040
23041 type_error:
23042 return DUK_RET_TYPE_ERROR;
23043}
23044#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23045DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
23046 DUK_UNREF(ctx);
23047 return DUK_RET_UNSUPPORTED_ERROR;
23048}
23049#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23050
23051/*
23052 * Node.js Buffer.prototype: toJSON()
23053 */
23054
23055#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23056DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
23057 duk_hthread *thr;
23058 duk_hbufferobject *h_this;
23059 duk_uint8_t *buf;
23060 duk_uint_t i;
23061
23062 thr = (duk_hthread *) ctx;
23063 DUK_UNREF(thr);
23064 h_this = duk__require_bufobj_this(ctx);
23065 DUK_ASSERT(h_this != NULL);
23066
23067 if (h_this->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
23068 /* Serialize uncovered backing buffer as a null; doesn't
23069 * really matter as long we're memory safe.
23070 */
23071 duk_push_null(ctx);
23072 return 1;
23073 }
23074
23075 duk_push_object(ctx);
23076 duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER);
23077 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_TYPE);
23078
23079 duk_push_array(ctx);
23080 for (i = 0; i < h_this->length; i++) {
23081 /* XXX: regetting the pointer may be overkill - we're writing
23082 * to a side-effect free array here.
23083 */
23084 DUK_ASSERT(h_this->buf != NULL);
23085 buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
23086 duk_push_uint(ctx, (duk_uint_t) buf[i]);
23087 duk_put_prop_index(ctx, -2, (duk_idx_t) i);
23088 }
23089 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_DATA);
23090
23091 return 1;
23092}
23093#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23094DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
23095 DUK_UNREF(ctx);
23096 return DUK_RET_UNSUPPORTED_ERROR;
23097}
23098#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23099
23100/*
23101 * Node.js Buffer.prototype.equals()
23102 * Node.js Buffer.prototype.compare()
23103 * Node.js Buffer.compare()
23104 */
23105
23106#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23107DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
23108 duk_hthread *thr;
23109 duk_small_uint_t magic;
23110 duk_hbufferobject *h_bufarg1;
23111 duk_hbufferobject *h_bufarg2;
23112 duk_small_int_t comp_res;
23113
23114 thr = (duk_hthread *) ctx;
23115 DUK_UNREF(thr);
23116
23117 magic = duk_get_current_magic(ctx);
23118 if (magic & 0x02) {
23119 /* Static call style. */
23120 h_bufarg1 = duk__require_bufobj_value(ctx, 0);
23121 h_bufarg2 = duk__require_bufobj_value(ctx, 1);
23122 } else {
23123 h_bufarg1 = duk__require_bufobj_this(ctx);
23124 h_bufarg2 = duk__require_bufobj_value(ctx, 0);
23125 }
23126 DUK_ASSERT(h_bufarg1 != NULL);
23127 DUK_ASSERT(h_bufarg2 != NULL);
23128
23129 /* We want to compare the slice/view areas of the arguments.
23130 * If either slice/view is invalid (underlying buffer is shorter)
23131 * ensure equals() is false, but otherwise the only thing that
23132 * matters is to be memory safe.
23133 */
23134
23135 if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg1) &&
23136 DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg2)) {
23137 comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
23138 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
23139 (duk_size_t) h_bufarg1->length,
23140 (duk_size_t) h_bufarg2->length);
23141 } else {
23142 comp_res = -1; /* either nonzero value is ok */
23143 }
23144
23145 if (magic & 0x01) {
23146 /* compare: similar to string comparison but for buffer data. */
23147 duk_push_int(ctx, comp_res);
23148 } else {
23149 /* equals */
23150 duk_push_boolean(ctx, (comp_res == 0));
23151 }
23152
23153 return 1;
23154}
23155#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23156DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
23157 DUK_UNREF(ctx);
23158 return DUK_RET_UNSUPPORTED_ERROR;
23159}
23160#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23161
23162/*
23163 * Node.js Buffer.prototype.fill()
23164 */
23165
23166#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23167DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
23168 duk_hthread *thr;
23169 duk_hbufferobject *h_this;
23170 const duk_uint8_t *fill_str_ptr;
23171 duk_size_t fill_str_len;
23172 duk_uint8_t fill_value;
23173 duk_int_t fill_offset;
23174 duk_int_t fill_end;
23175 duk_size_t fill_length;
23176 duk_uint8_t *p;
23177
23178 thr = (duk_hthread *) ctx;
23179 DUK_UNREF(thr);
23180
23181 h_this = duk__require_bufobj_this(ctx);
23182 DUK_ASSERT(h_this != NULL);
23183 if (h_this->buf == NULL) {
23184 return DUK_RET_TYPE_ERROR;
23185 }
23186
23187 /* [ value offset end ] */
23188
23189 if (duk_is_string(ctx, 0)) {
23190 fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len);
23191 DUK_ASSERT(fill_str_ptr != NULL);
23192 } else {
23193 fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0);
23194 fill_str_ptr = (const duk_uint8_t *) &fill_value;
23195 fill_str_len = 1;
23196 }
23197
23198 /* Fill offset handling is more lenient than in Node.js. */
23199
23200 duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &fill_offset, &fill_end);
23201
23202 DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
23203 (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
23204
23205 DUK_ASSERT(fill_end - fill_offset >= 0);
23206 DUK_ASSERT(h_this->buf != NULL);
23207
23208 p = (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
23209 fill_length = (duk_size_t) (fill_end - fill_offset);
23210 if (fill_str_len == 1) {
23211 /* Handle single character fills as memset() even when
23212 * the fill data comes from a one-char argument.
23213 */
23214 DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
23215 } else if (fill_str_len > 1) {
23216 duk_size_t i, n, t;
23217
23218 for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) {
23219 p[i] = fill_str_ptr[t++];
23220 if (t >= fill_str_len) {
23221 t = 0;
23222 }
23223 }
23224 } else {
23225 DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently"));
23226 }
23227
23228 /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
23229 duk_push_this(ctx);
23230 return 1;
23231}
23232#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23233DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
23234 DUK_UNREF(ctx);
23235 return DUK_RET_UNSUPPORTED_ERROR;
23236}
23237#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23238
23239/*
23240 * Node.js Buffer.prototype.write(string, [offset], [length], [encoding])
23241 */
23242
23243#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23244DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
23245 duk_hthread *thr;
23246 duk_hbufferobject *h_this;
23247 duk_uint_t offset;
23248 duk_uint_t length;
23249 const duk_uint8_t *str_data;
23250 duk_size_t str_len;
23251
23252 thr = (duk_hthread *) ctx;
23253 DUK_UNREF(thr);
23254
23255 h_this = duk__require_bufobj_this(ctx);
23256 DUK_ASSERT(h_this != NULL);
23257
23258 /* Argument must be a string, e.g. a buffer is not allowed. */
23259 str_data = (const duk_uint8_t *) duk_require_lstring(ctx, 0, &str_len);
23260
23261 duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
23262 DUK_ASSERT(offset <= h_this->length);
23263 DUK_ASSERT(offset + length <= h_this->length);
23264
23265 /* XXX: encoding is ignored now. */
23266
23267 if (length > str_len) {
23268 length = (duk_uint_t) str_len;
23269 }
23270
23271 if (DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
23272 /* Cannot overlap. */
23273 DUK_MEMCPY((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset),
23274 (const void *) str_data,
23275 (size_t) length);
23276 } else {
23277 DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
23278 }
23279
23280 duk_push_uint(ctx, length);
23281 return 1;
23282}
23283#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23284DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
23285 DUK_UNREF(ctx);
23286 return DUK_RET_UNSUPPORTED_ERROR;
23287}
23288#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23289
23290/*
23291 * Node.js Buffer.prototype.copy()
23292 */
23293
23294#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23295DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
23296 duk_hthread *thr;
23297 duk_hbufferobject *h_this;
23298 duk_hbufferobject *h_bufarg;
23299 duk_int_t source_length;
23300 duk_int_t target_length;
23301 duk_int_t target_start, source_start, source_end;
23302 duk_uint_t target_ustart, source_ustart, source_uend;
23303 duk_uint_t copy_size = 0;
23304
23305 /* [ targetBuffer targetStart sourceStart sourceEnd ] */
23306
23307 thr = (duk_hthread *) ctx;
23308 DUK_UNREF(thr);
23309
23310 h_this = duk__require_bufobj_this(ctx);
23311 h_bufarg = duk__require_bufobj_value(ctx, 0);
23312 DUK_ASSERT(h_this != NULL);
23313 DUK_ASSERT(h_bufarg != NULL);
23314 source_length = (duk_int_t) h_this->length;
23315 target_length = (duk_int_t) h_bufarg->length;
23316
23317 target_start = duk_to_int(ctx, 1);
23318 source_start = duk_to_int(ctx, 2);
23319 if (duk_is_undefined(ctx, 3)) {
23320 source_end = source_length;
23321 } else {
23322 source_end = duk_to_int(ctx, 3);
23323 }
23324
23325 DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
23326 "source_start=%ld, source_end=%ld, source_length=%ld",
23327 (long) target_start, (long) h_bufarg->length,
23328 (long) source_start, (long) source_end, (long) source_length));
23329
23330 /* This behavior mostly mimics Node.js now. */
23331
23332 if (source_start < 0 || source_end < 0 || target_start < 0) {
23333 /* Negative offsets cause a RangeError. */
23334 goto fail_bounds;
23335 }
23336 source_ustart = (duk_uint_t) source_start;
23337 source_uend = (duk_uint_t) source_end;
23338 target_ustart = (duk_uint_t) target_start;
23339 if (source_ustart >= source_uend || /* crossed offsets or zero size */
23340 source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */
23341 target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */
23342 goto silent_ignore;
23343 }
23344 if (source_uend >= (duk_uint_t) source_length) {
23345 /* Source end clamped silently to available length. */
23346 source_uend = source_length;
23347 }
23348 copy_size = source_uend - source_ustart;
23349 if (target_ustart + copy_size > (duk_uint_t) target_length) {
23350 /* Clamp to target's end if too long.
23351 *
23352 * NOTE: there's no overflow possibility in the comparison;
23353 * both target_ustart and copy_size are >= 0 and based on
23354 * values in duk_int_t range. Adding them as duk_uint_t
23355 * values is then guaranteed not to overflow.
23356 */
23357 DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */
23358 DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */
23359 copy_size = (duk_uint_t) target_length - target_ustart;
23360 }
23361
23362 DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu",
23363 (unsigned long) target_ustart, (unsigned long) source_ustart,
23364 (unsigned long) copy_size));
23365
23366 DUK_ASSERT(copy_size >= 1);
23367 DUK_ASSERT(source_ustart <= (duk_uint_t) source_length);
23368 DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length);
23369 DUK_ASSERT(target_ustart <= (duk_uint_t) target_length);
23370 DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length);
23371
23372 /* Ensure copy is covered by underlying buffers. */
23373 DUK_ASSERT(h_bufarg->buf != NULL); /* length check */
23374 DUK_ASSERT(h_this->buf != NULL); /* length check */
23375 if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
23376 DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
23377 /* Must use memmove() because copy area may overlap (source and target
23378 * buffer may be the same, or from different slices.
23379 */
23380 DUK_MEMMOVE((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
23381 (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
23382 (size_t) copy_size);
23383 } else {
23384 DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
23385 }
23386
23387 silent_ignore:
23388 /* Return value is like write(), number of bytes written.
23389 * The return value matters because of code like:
23390 * "off += buf.copy(...)".
23391 */
23392 duk_push_uint(ctx, copy_size);
23393 return 1;
23394
23395 fail_bounds:
23396 return DUK_RET_RANGE_ERROR;
23397}
23398#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23399DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
23400 DUK_UNREF(ctx);
23401 return DUK_RET_UNSUPPORTED_ERROR;
23402}
23403#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23404
23405/*
23406 * TypedArray.prototype.set()
23407 *
23408 * TypedArray set() is pretty interesting to implement because:
23409 *
23410 * - The source argument may be a plain array or a typedarray. If the
23411 * source is a TypedArray, values are decoded and re-encoded into the
23412 * target (not as a plain byte copy). This may happen even when the
23413 * element byte size is the same, e.g. integer values may be re-encoded
23414 * into floats.
23415 *
23416 * - Source and target may refer to the same underlying buffer, so that
23417 * the set() operation may overlap. The specification requires that this
23418 * must work as if a copy was made before the operation. Note that this
23419 * is NOT a simple memmove() situation because the source and target
23420 * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may
23421 * expand to a 16-byte target (Uint32Array) so that the target overlaps
23422 * the source both from beginning and the end (unlike in typical memmove).
23423 *
23424 * - Even if 'buf' pointers of the source and target differ, there's no
23425 * guarantee that their memory areas don't overlap. This may be the
23426 * case with external buffers.
23427 *
23428 * Even so, it is nice to optimize for the common case:
23429 *
23430 * - Source and target separate buffers or non-overlapping.
23431 *
23432 * - Source and target have a compatible type so that a plain byte copy
23433 * is possible. Note that while e.g. uint8 and int8 are compatible
23434 * (coercion one way or another doesn't change the byte representation),
23435 * e.g. int8 and uint8clamped are NOT compatible when writing int8
23436 * values into uint8clamped typedarray (-1 would clamp to 0 for instance).
23437 *
23438 * See test-bi-typedarray-proto-set.js.
23439 */
23440
23441#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23442DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
23443 duk_hthread *thr;
23444 duk_hbufferobject *h_this;
23445 duk_hobject *h_obj;
23446 duk_uarridx_t i, n;
23447 duk_int_t offset_signed;
23448 duk_uint_t offset_elems;
23449 duk_uint_t offset_bytes;
23450
23451 thr = (duk_hthread *) ctx;
23452 DUK_UNREF(thr);
23453
23454 h_this = duk__require_bufobj_this(ctx);
23455 DUK_ASSERT(h_this != NULL);
23456 DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
23457
23458 if (h_this->buf == NULL) {
23459 DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
23460 return 0;
23461 }
23462
23463 h_obj = duk_require_hobject(ctx, 0);
23464 DUK_ASSERT(h_obj != NULL);
23465
23466 /* XXX: V8 throws a TypeError for negative values. Would it
23467 * be more useful to interpret negative offsets here from the
23468 * end of the buffer too?
23469 */
23470 offset_signed = duk_to_int(ctx, 1);
23471 if (offset_signed < 0) {
23472 return DUK_RET_TYPE_ERROR;
23473 }
23474 offset_elems = (duk_uint_t) offset_signed;
23475 offset_bytes = offset_elems << h_this->shift;
23476 if ((offset_bytes >> h_this->shift) != offset_elems) {
23477 /* Byte length would overflow. */
23478 /* XXX: easier check with less code? */
23479 return DUK_RET_RANGE_ERROR;
23480 }
23481 if (offset_bytes > h_this->length) {
23482 /* Equality may be OK but >length not. Checking
23483 * this explicitly avoids some overflow cases
23484 * below.
23485 */
23486 return DUK_RET_RANGE_ERROR;
23487 }
23488 DUK_ASSERT(offset_bytes <= h_this->length);
23489
23490 /* Fast path: source is a TypedArray (or any bufferobject). */
23491
23492 if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
23493 duk_hbufferobject *h_bufarg;
23494 duk_uint16_t comp_mask;
23495 duk_small_int_t no_overlap = 0;
23496 duk_uint_t src_length;
23497 duk_uint_t dst_length;
23498 duk_uint_t dst_length_elems;
23499 duk_uint8_t *p_src_base;
23500 duk_uint8_t *p_src_end;
23501 duk_uint8_t *p_src;
23502 duk_uint8_t *p_dst_base;
23503 duk_uint8_t *p_dst;
23504 duk_small_uint_t src_elem_size;
23505 duk_small_uint_t dst_elem_size;
23506
23507 h_bufarg = (duk_hbufferobject *) h_obj;
23508 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
23509
23510 if (h_bufarg->buf == NULL) {
23511 DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
23512 return 0;
23513 }
23514
23515 /* Nominal size check. */
23516 src_length = h_bufarg->length; /* bytes in source */
23517 dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */
23518 dst_length = dst_length_elems << h_this->shift; /* bytes in dest */
23519 if ((dst_length >> h_this->shift) != dst_length_elems) {
23520 /* Byte length would overflow. */
23521 /* XXX: easier check with less code? */
23522 return DUK_RET_RANGE_ERROR;
23523 }
23524 DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
23525 (long) src_length, (long) dst_length));
23526 DUK_ASSERT(offset_bytes <= h_this->length);
23527 if (dst_length > h_this->length - offset_bytes) {
23528 /* Overflow not an issue because subtraction is used on the right
23529 * side and guaranteed to be >= 0.
23530 */
23531 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
23532 return DUK_RET_RANGE_ERROR;
23533 }
23534 if (!DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
23535 DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
23536 return 0;
23537 }
23538
23539 p_src_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
23540 p_dst_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
23541
23542 /* Check actual underlying buffers for validity and that they
23543 * cover the copy. No side effects are allowed after the check
23544 * so that the validity status doesn't change.
23545 */
23546 if (!DUK_HBUFFEROBJECT_VALID_SLICE(h_this) ||
23547 !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
23548 /* The condition could be more narrow and check for the
23549 * copy area only, but there's no need for fine grained
23550 * behavior when the underlying buffer is misconfigured.
23551 */
23552 DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy"));
23553 return 0;
23554 }
23555
23556 /* We want to do a straight memory copy if possible: this is
23557 * an important operation because .set() is the TypedArray
23558 * way to copy chunks of memory. However, because set()
23559 * conceptually works in terms of elements, not all views are
23560 * compatible with direct byte copying.
23561 *
23562 * If we do manage a direct copy, the "overlap issue" handled
23563 * below can just be solved using memmove() because the source
23564 * and destination element sizes are necessarily equal.
23565 */
23566
23567 DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
23568 comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
23569 if (comp_mask & (1 << h_bufarg->elem_type)) {
23570 DUK_ASSERT(src_length == dst_length);
23571
23572 DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
23573 DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
23574 return 0;
23575 }
23576 DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
23577
23578 /* We want to avoid making a copy to process set() but that's
23579 * not always possible: the source and the target may overlap
23580 * and because element sizes are different, the overlap cannot
23581 * always be handled with a memmove() or choosing the copy
23582 * direction in a certain way. For example, if source type is
23583 * uint8 and target type is uint32, the target area may exceed
23584 * the source area from both ends!
23585 *
23586 * Note that because external buffers may point to the same
23587 * memory areas, we must ultimately make this check using
23588 * pointers.
23589 *
23590 * NOTE: careful with side effects: any side effect may cause
23591 * a buffer resize (or external buffer pointer/length update)!
23592 */
23593
23594 DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, "
23595 "p_dst_base=%p, dst_length=%ld",
23596 (void *) p_src_base, (long) src_length,
23597 (void *) p_dst_base, (long) dst_length));
23598
23599 if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */
23600 p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */
23601 no_overlap = 1;
23602 }
23603
23604 if (!no_overlap) {
23605 /* There's overlap: the desired end result is that
23606 * conceptually a copy is made to avoid "trampling"
23607 * of source data by destination writes. We make
23608 * an actual temporary copy to handle this case.
23609 */
23610 duk_uint8_t *p_src_copy;
23611
23612 DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
23613 p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_length);
23614 DUK_ASSERT(p_src_copy != NULL);
23615 DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
23616
23617 p_src_base = p_src_copy; /* use p_src_base from now on */
23618 }
23619 /* Value stack intentionally mixed size here. */
23620
23621 DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, "
23622 "p_dst_base=%p, dst_length=%ld, valstack top=%ld",
23623 (void *) p_src_base, (long) src_length,
23624 (void *) p_dst_base, (long) dst_length,
23625 (long) duk_get_top(ctx)));
23626
23627 /* Ready to make the copy. We must proceed element by element
23628 * and must avoid any side effects that might cause the buffer
23629 * validity check above to become invalid.
23630 *
23631 * Although we work through the value stack here, only plain
23632 * numbers are handled which should be side effect safe.
23633 */
23634
23635 src_elem_size = 1 << h_bufarg->shift;
23636 dst_elem_size = 1 << h_this->shift;
23637 p_src = p_src_base;
23638 p_dst = p_dst_base;
23639 p_src_end = p_src_base + src_length;
23640
23641 while (p_src != p_src_end) {
23642 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
23643 "p_src=%p, p_src_end=%p, p_dst=%p",
23644 (void *) p_src, (void *) p_src_end, (void *) p_dst));
23645 /* A validated read() is always a number, so it's write coercion
23646 * is always side effect free an won't invalidate pointers etc.
23647 */
23648 duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
23649 duk_hbufferobject_validated_write(ctx, h_this, p_dst, dst_elem_size);
23650 duk_pop(ctx);
23651 p_src += src_elem_size;
23652 p_dst += dst_elem_size;
23653 }
23654
23655 return 0;
23656 } else {
23657 /* Slow path: quite slow, but we save space by using the property code
23658 * to write coerce target values. We don't need to worry about overlap
23659 * here because the source is not a TypedArray.
23660 *
23661 * We could use the bufferobject write coercion helper but since the
23662 * property read may have arbitrary side effects, full validity checks
23663 * would be needed for every element anyway.
23664 */
23665
23666 n = (duk_uarridx_t) duk_get_length(ctx, 0);
23667 DUK_ASSERT(offset_bytes <= h_this->length);
23668 if ((n << h_this->shift) > h_this->length - offset_bytes) {
23669 /* Overflow not an issue because subtraction is used on the right
23670 * side and guaranteed to be >= 0.
23671 */
23672 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
23673 return DUK_RET_RANGE_ERROR;
23674 }
23675
23676 /* There's no need to check for buffer validity status for the
23677 * target here: the property access code will do that for each
23678 * element. Moreover, if we did check the validity here, side
23679 * effects from reading the source argument might invalidate
23680 * the results anyway.
23681 */
23682
23683 DUK_ASSERT_TOP(ctx, 2);
23684 duk_push_this(ctx);
23685
23686 for (i = 0; i < n; i++) {
23687 duk_get_prop_index(ctx, 0, i);
23688 duk_put_prop_index(ctx, 2, offset_elems + i);
23689 }
23690 }
23691
23692 return 0;
23693}
23694#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23695DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
23696 DUK_UNREF(ctx);
23697 return DUK_RET_UNSUPPORTED_ERROR;
23698}
23699#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23700
23701/*
23702 * Node.js Buffer.prototype.slice([start], [end])
23703 * ArrayBuffer.prototype.slice(begin, [end])
23704 * TypedArray.prototype.slice(begin, [end])
23705 *
23706 * The API calls are almost identical; negative indices are counted from end
23707 * of buffer, and final indices are clamped (allowing crossed indices). Main
23708 * differences:
23709 *
23710 * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create
23711 * views, ArrayBuffer .slice() creates a copy
23712 *
23713 * - Resulting object has a different class and prototype depending on the
23714 * call (or 'this' argument)
23715 *
23716 * - TypedArray .subarray() arguments are element indices, not byte offsets
23717 */
23718
23719#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23720DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
23721 duk_hthread *thr;
23722 duk_small_int_t magic;
23723 duk_small_uint_t res_class_num;
23724 duk_hobject *res_proto;
23725 duk_hbufferobject *h_this;
23726 duk_hbufferobject *h_bufobj;
23727 duk_hbuffer *h_val;
23728 duk_int_t start_offset, end_offset;
23729 duk_uint_t slice_length;
23730
23731 thr = (duk_hthread *) ctx;
23732 DUK_UNREF(thr);
23733
23734 /* [ start end ] */
23735
23736 magic = duk_get_current_magic(ctx);
23737 h_this = duk__require_bufobj_this(ctx);
23738
23739 /* Slice offsets are element (not byte) offsets, which only matters
23740 * for TypedArray views, Node.js Buffer and ArrayBuffer have shift
23741 * zero so byte and element offsets are the same. Negative indices
23742 * are counted from end of slice, crossed indices are allowed (and
23743 * result in zero length result), and final values are clamped
23744 * against the current slice. There's intentionally no check
23745 * against the underlying buffer here.
23746 */
23747
23748 duk__clamp_startend_negidx_shifted(ctx, h_this, 0 /*idx_start*/, 1 /*idx_end*/, &start_offset, &end_offset);
23749 DUK_ASSERT(end_offset >= start_offset);
23750 slice_length = (duk_uint_t) (end_offset - start_offset);
23751
23752 /* The resulting buffer object gets the same class and prototype as
23753 * the buffer in 'this', e.g. if the input is a Node.js Buffer the
23754 * result is a Node.js Buffer; if the input is a Float32Array, the
23755 * result is a Float32Array.
23756 *
23757 * For the class number this seems correct. The internal prototype
23758 * is not so clear: if 'this' is a bufferobject with a non-standard
23759 * prototype object, that value gets copied over into the result
23760 * (instead of using the standard prototype for that object type).
23761 */
23762
23763 res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
23764 h_bufobj = duk_push_bufferobject_raw(ctx,
23765 DUK_HOBJECT_FLAG_EXTENSIBLE |
23766 DUK_HOBJECT_FLAG_BUFFEROBJECT |
23767 DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
23768 DUK_BIDX_OBJECT_PROTOTYPE); /* replaced */
23769 DUK_ASSERT(h_bufobj != NULL);
23770 res_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_this); /* may be NULL */
23771 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_bufobj, res_proto);
23772
23773 DUK_ASSERT(h_bufobj->length == 0);
23774 h_bufobj->shift = h_this->shift; /* inherit */
23775 h_bufobj->elem_type = h_this->elem_type; /* inherit */
23776 h_bufobj->is_view = magic & 0x01;
23777 DUK_ASSERT(h_bufobj->is_view == 0 || h_bufobj->is_view == 1);
23778
23779 h_val = h_this->buf;
23780 if (h_val == NULL) {
23781 return DUK_RET_TYPE_ERROR;
23782 }
23783
23784 if (magic & 0x02) {
23785 /* non-zero: make copy */
23786 duk_uint8_t *p_copy;
23787 duk_size_t copy_length;
23788
23789 p_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) slice_length);
23790 DUK_ASSERT(p_copy != NULL);
23791
23792 /* Copy slice, respecting underlying buffer limits; remainder
23793 * is left as zero.
23794 */
23795 copy_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, slice_length);
23796 DUK_MEMCPY((void *) p_copy,
23797 (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
23798 copy_length);
23799
23800 h_val = duk_get_hbuffer(ctx, -1);
23801 DUK_ASSERT(h_val != NULL);
23802
23803 h_bufobj->buf = h_val;
23804 DUK_HBUFFER_INCREF(thr, h_val);
23805 h_bufobj->length = slice_length;
23806 DUK_ASSERT(h_bufobj->offset == 0);
23807
23808 duk_pop(ctx); /* reachable so pop OK */
23809 } else {
23810 h_bufobj->buf = h_val;
23811 DUK_HBUFFER_INCREF(thr, h_val);
23812 h_bufobj->length = slice_length;
23813 h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset);
23814
23815 /* Copy the .buffer property, needed for TypedArray.prototype.subarray().
23816 *
23817 * XXX: limit copy only for TypedArray classes specifically?
23818 */
23819
23820 duk_push_this(ctx);
23821 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_BUFFER)) {
23822 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
23823 duk_pop(ctx);
23824 } else {
23825 duk_pop_2(ctx);
23826 }
23827 }
23828 /* unbalanced stack on purpose */
23829
23830 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
23831 return 1;
23832}
23833#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23834DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
23835 DUK_UNREF(ctx);
23836 return DUK_RET_UNSUPPORTED_ERROR;
23837}
23838#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23839
23840/*
23841 * Node.js Buffer.isEncoding()
23842 */
23843
23844#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23845DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
23846 const char *encoding;
23847
23848 /* only accept lowercase 'utf8' now. */
23849
23850 encoding = duk_to_string(ctx, 0);
23851 DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */
23852 duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0);
23853 return 1;
23854}
23855#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23856DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
23857 DUK_UNREF(ctx);
23858 return DUK_RET_UNSUPPORTED_ERROR;
23859}
23860#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23861
23862/*
23863 * Node.js Buffer.isBuffer()
23864 */
23865
23866#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23867DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
23868 duk_hthread *thr;
23869 duk_tval *tv;
23870 duk_hobject *h;
23871 duk_hobject *h_proto;
23872 duk_bool_t ret = 0;
23873
23874 thr = (duk_hthread *) ctx;
23875
23876 DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */
23877 tv = duk_get_tval(ctx, 0);
23878 DUK_ASSERT(tv != NULL);
23879
23880 if (DUK_TVAL_IS_OBJECT(tv)) {
23881 h = DUK_TVAL_GET_OBJECT(tv);
23882 DUK_ASSERT(h != NULL);
23883
23884 h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
23885 DUK_ASSERT(h_proto != NULL);
23886
23887 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
23888 if (h) {
23889 ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
23890 }
23891 }
23892
23893 duk_push_boolean(ctx, ret);
23894 return 1;
23895}
23896#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23897DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
23898 DUK_UNREF(ctx);
23899 return DUK_RET_UNSUPPORTED_ERROR;
23900}
23901#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23902
23903/*
23904 * Node.js Buffer.byteLength()
23905 */
23906
23907#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23908DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
23909 const char *str;
23910 duk_size_t len;
23911
23912 /* At the moment Buffer(<str>) will just use the string bytes as
23913 * is (ignoring encoding), so we return the string length here
23914 * unconditionally.
23915 */
23916
23917 str = duk_to_lstring(ctx, 0, &len);
23918 DUK_UNREF(str);
23919 duk_push_size_t(ctx, len);
23920 return 1;
23921}
23922#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23923DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
23924 DUK_UNREF(ctx);
23925 return DUK_RET_UNSUPPORTED_ERROR;
23926}
23927#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23928
23929/*
23930 * Node.js Buffer.concat()
23931 */
23932
23933#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23934DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
23935 duk_hthread *thr;
23936 duk_hobject *h_arg;
23937 duk_int_t total_length = 0;
23938 duk_hbufferobject *h_bufobj;
23939 duk_hbufferobject *h_bufres;
23940 duk_hbuffer *h_val;
23941 duk_uint_t i, n;
23942 duk_uint8_t *p;
23943 duk_size_t space_left;
23944 duk_size_t copy_size;
23945
23946 thr = (duk_hthread *) ctx;
23947 DUK_UNREF(thr);
23948
23949 /* Node.js accepts only actual Arrays. */
23950 h_arg = duk_require_hobject(ctx, 0);
23951 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
23952 return DUK_RET_TYPE_ERROR;
23953 }
23954
23955 /* Compute result length and validate argument buffers. */
23956 n = (duk_uint_t) duk_get_length(ctx, 0);
23957 for (i = 0; i < n; i++) {
23958 /* Neutered checks not necessary here: neutered buffers have
23959 * zero 'length' so we'll effectively skip them.
23960 */
23961 DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */
23962 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
23963 h_bufobj = duk__require_bufobj_value(ctx, 2);
23964 DUK_ASSERT(h_bufobj != NULL);
23965 total_length += h_bufobj->length;
23966 duk_pop(ctx);
23967 }
23968 if (n == 1) {
23969 /* For the case n==1 Node.js doesn't seem to type check
23970 * the sole member but we do it before returning it.
23971 * For this case only the original buffer object is
23972 * returned (not a copy).
23973 */
23974 duk_get_prop_index(ctx, 0, 0);
23975 return 1;
23976 }
23977
23978 /* User totalLength overrides a computed length, but we'll check
23979 * every copy in the copy loop. Note that duk_to_uint() can
23980 * technically have arbitrary side effects so we need to recheck
23981 * the buffers in the copy loop.
23982 */
23983 if (!duk_is_undefined(ctx, 1) && n > 0) {
23984 /* For n == 0, Node.js ignores totalLength argument and
23985 * returns a zero length buffer.
23986 */
23987 total_length = duk_to_int(ctx, 1);
23988 }
23989 if (total_length < 0) {
23990 return DUK_RET_RANGE_ERROR;
23991 }
23992
23993 h_bufres = duk_push_bufferobject_raw(ctx,
23994 DUK_HOBJECT_FLAG_EXTENSIBLE |
23995 DUK_HOBJECT_FLAG_BUFFEROBJECT |
23996 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
23997 DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
23998 DUK_ASSERT(h_bufres != NULL);
23999
24000 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, total_length);
24001 DUK_ASSERT(p != NULL);
24002 space_left = total_length;
24003
24004 for (i = 0; i < n; i++) {
24005 DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */
24006
24007 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
24008 h_bufobj = duk__require_bufobj_value(ctx, 4);
24009 DUK_ASSERT(h_bufobj != NULL);
24010
24011 copy_size = h_bufobj->length;
24012 if (copy_size > space_left) {
24013 copy_size = space_left;
24014 }
24015
24016 if (h_bufobj->buf != NULL &&
24017 DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
24018 DUK_MEMCPY((void *) p,
24019 (const void *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj),
24020 copy_size);
24021 } else {
24022 /* Just skip, leaving zeroes in the result. */
24023 ;
24024 }
24025 p += copy_size;
24026 space_left -= copy_size;
24027
24028 duk_pop(ctx);
24029 }
24030
24031 h_val = duk_get_hbuffer(ctx, -1);
24032 DUK_ASSERT(h_val != NULL);
24033
24034 duk__set_bufobj_buffer(ctx, h_bufres, h_val);
24035 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufres);
24036
24037 duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */
24038
24039 return 1; /* return h_bufres */
24040}
24041#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
24042DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
24043 DUK_UNREF(ctx);
24044 return DUK_RET_UNSUPPORTED_ERROR;
24045}
24046#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24047
24048/*
24049 * Shared readfield and writefield methods
24050 *
24051 * The readfield/writefield methods need support for endianness and field
24052 * types. All offsets are byte based so no offset shifting is needed.
24053 */
24054
24055#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24056/* Format of magic, bits:
24057 * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused
24058 * 3: endianness: 0=little, 1=big
24059 * 4: signed: 1=yes, 0=no
24060 * 5: typedarray: 1=yes, 0=no
24061 */
24062#define DUK__FLD_8BIT 0
24063#define DUK__FLD_16BIT 1
24064#define DUK__FLD_32BIT 2
24065#define DUK__FLD_FLOAT 3
24066#define DUK__FLD_DOUBLE 4
24067#define DUK__FLD_VARINT 5
24068#define DUK__FLD_BIGENDIAN (1 << 3)
24069#define DUK__FLD_SIGNED (1 << 4)
24070#define DUK__FLD_TYPEDARRAY (1 << 5)
24071
24072/* XXX: split into separate functions for each field type? */
24073DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
24074 duk_hthread *thr;
24075 duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
24076 duk_small_int_t magic_ftype;
24077 duk_small_int_t magic_bigendian;
24078 duk_small_int_t magic_signed;
24079 duk_small_int_t magic_typedarray;
24080 duk_small_int_t endswap;
24081 duk_hbufferobject *h_this;
24082 duk_bool_t no_assert;
24083 duk_int_t offset_signed;
24084 duk_uint_t offset;
24085 duk_uint_t buffer_length;
24086 duk_uint_t check_length;
24087 duk_uint8_t *buf;
24088 duk_double_union du;
24089
24090 thr = (duk_hthread *) ctx;
24091 DUK_UNREF(thr);
24092
24093 magic_ftype = magic & 0x0007;
24094 magic_bigendian = magic & 0x0008;
24095 magic_signed = magic & 0x0010;
24096 magic_typedarray = magic & 0x0020;
24097
24098 h_this = duk__require_bufobj_this(ctx);
24099 DUK_ASSERT(h_this != NULL);
24100 buffer_length = h_this->length;
24101
24102 /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */
24103 /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
24104 /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
24105
24106 /* Handle TypedArray vs. Node.js Buffer arg differences */
24107 if (magic_typedarray) {
24108 no_assert = 0;
24109#if defined(DUK_USE_INTEGER_LE)
24110 endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */
24111#else
24112 endswap = duk_to_boolean(ctx, 1); /* 1=little endian */
24113#endif
24114 } else {
24115 no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
24116#if defined(DUK_USE_INTEGER_LE)
24117 endswap = magic_bigendian;
24118#else
24119 endswap = !magic_bigendian;
24120#endif
24121 }
24122
24123 /* Offset is coerced first to signed integer range and then to unsigned.
24124 * This ensures we can add a small byte length (1-8) to the offset in
24125 * bound checks and not wrap.
24126 */
24127 offset_signed = duk_to_int(ctx, 0);
24128 offset = (duk_uint_t) offset_signed;
24129 if (offset_signed < 0) {
24130 goto fail_bounds;
24131 }
24132
24133 DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, "
24134 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
24135 "endswap=%d",
24136 (long) buffer_length, (long) offset, (int) no_assert,
24137 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
24138 (int) (magic_signed >> 4), (int) endswap));
24139
24140 /* Update 'buffer_length' to be the effective, safe limit which
24141 * takes into account the underlying buffer. This value will be
24142 * potentially invalidated by any side effect.
24143 */
24144 check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
24145 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
24146 (long) buffer_length, (long) check_length));
24147
24148 if (h_this->buf) {
24149 buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
24150 } else {
24151 /* Neutered. We could go into the switch-case safely with
24152 * buf == NULL because check_length == 0. To avoid scanbuild
24153 * warnings, fail directly instead.
24154 */
24155 DUK_ASSERT(check_length == 0);
24156 goto fail_neutered;
24157 }
24158 DUK_ASSERT(buf != NULL);
24159
24160 switch (magic_ftype) {
24161 case DUK__FLD_8BIT: {
24162 duk_uint8_t tmp;
24163 if (offset + 1U > check_length) {
24164 goto fail_bounds;
24165 }
24166 tmp = buf[offset];
24167 if (magic_signed) {
24168 duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp));
24169 } else {
24170 duk_push_uint(ctx, (duk_uint_t) tmp);
24171 }
24172 break;
24173 }
24174 case DUK__FLD_16BIT: {
24175 duk_uint16_t tmp;
24176 if (offset + 2U > check_length) {
24177 goto fail_bounds;
24178 }
24179 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2);
24180 tmp = du.us[0];
24181 if (endswap) {
24182 tmp = DUK_BSWAP16(tmp);
24183 }
24184 if (magic_signed) {
24185 duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp));
24186 } else {
24187 duk_push_uint(ctx, (duk_uint_t) tmp);
24188 }
24189 break;
24190 }
24191 case DUK__FLD_32BIT: {
24192 duk_uint32_t tmp;
24193 if (offset + 4U > check_length) {
24194 goto fail_bounds;
24195 }
24196 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
24197 tmp = du.ui[0];
24198 if (endswap) {
24199 tmp = DUK_BSWAP32(tmp);
24200 }
24201 if (magic_signed) {
24202 duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp));
24203 } else {
24204 duk_push_uint(ctx, (duk_uint_t) tmp);
24205 }
24206 break;
24207 }
24208 case DUK__FLD_FLOAT: {
24209 duk_uint32_t tmp;
24210 if (offset + 4U > check_length) {
24211 goto fail_bounds;
24212 }
24213 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
24214 if (endswap) {
24215 tmp = du.ui[0];
24216 tmp = DUK_BSWAP32(tmp);
24217 du.ui[0] = tmp;
24218 }
24219 duk_push_number(ctx, (duk_double_t) du.f[0]);
24220 break;
24221 }
24222 case DUK__FLD_DOUBLE: {
24223 if (offset + 8U > check_length) {
24224 goto fail_bounds;
24225 }
24226 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8);
24227 if (endswap) {
24228 DUK_DBLUNION_BSWAP64(&du);
24229 }
24230 duk_push_number(ctx, (duk_double_t) du.d);
24231 break;
24232 }
24233 case DUK__FLD_VARINT: {
24234 /* Node.js Buffer variable width integer field. We don't really
24235 * care about speed here, so aim for shortest algorithm.
24236 */
24237 duk_int_t field_bytelen;
24238 duk_int_t i, i_step, i_end;
24239#if defined(DUK_USE_64BIT_OPS)
24240 duk_int64_t tmp;
24241 duk_small_uint_t shift_tmp;
24242#else
24243 duk_double_t tmp;
24244 duk_small_int_t highbyte;
24245#endif
24246 const duk_uint8_t *p;
24247
24248 field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */
24249 if (field_bytelen < 1 || field_bytelen > 6) {
24250 goto fail_field_length;
24251 }
24252 if (offset + (duk_uint_t) field_bytelen > check_length) {
24253 goto fail_bounds;
24254 }
24255 p = (const duk_uint8_t *) (buf + offset);
24256
24257 /* Slow gathering of value using either 64-bit arithmetic
24258 * or IEEE doubles if 64-bit types not available. Handling
24259 * of negative numbers is a bit non-obvious in both cases.
24260 */
24261
24262 if (magic_bigendian) {
24263 /* Gather in big endian */
24264 i = 0;
24265 i_step = 1;
24266 i_end = field_bytelen; /* one i_step over */
24267 } else {
24268 /* Gather in little endian */
24269 i = field_bytelen - 1;
24270 i_step = -1;
24271 i_end = -1; /* one i_step over */
24272 }
24273
24274#if defined(DUK_USE_64BIT_OPS)
24275 tmp = 0;
24276 do {
24277 DUK_ASSERT(i >= 0 && i < field_bytelen);
24278 tmp = (tmp << 8) + (duk_int64_t) p[i];
24279 i += i_step;
24280 } while (i != i_end);
24281
24282 if (magic_signed) {
24283 /* Shift to sign extend. */
24284 shift_tmp = 64 - (field_bytelen * 8);
24285 tmp = (tmp << shift_tmp) >> shift_tmp;
24286 }
24287
24288 duk_push_i64(ctx, tmp);
24289#else
24290 highbyte = p[i];
24291 if (magic_signed && (highbyte & 0x80) != 0) {
24292 /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */
24293 tmp = (duk_double_t) (highbyte - 256);
24294 } else {
24295 tmp = (duk_double_t) highbyte;
24296 }
24297 for (;;) {
24298 i += i_step;
24299 if (i == i_end) {
24300 break;
24301 }
24302 DUK_ASSERT(i >= 0 && i < field_bytelen);
24303 tmp = (tmp * 256.0) + (duk_double_t) p[i];
24304 }
24305
24306 duk_push_number(ctx, tmp);
24307#endif
24308 break;
24309 }
24310 default: { /* should never happen but default here */
24311 goto fail_bounds;
24312 }
24313 }
24314
24315 return 1;
24316
24317 fail_neutered:
24318 fail_field_length:
24319 fail_bounds:
24320 if (no_assert) {
24321 /* Node.js return value for noAssert out-of-bounds reads is
24322 * usually (but not always) NaN. Return NaN consistently.
24323 */
24324 duk_push_nan(ctx);
24325 return 1;
24326 }
24327
24328 return DUK_RET_RANGE_ERROR;
24329}
24330#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
24331DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
24332 DUK_UNREF(ctx);
24333 return DUK_RET_UNSUPPORTED_ERROR;
24334}
24335#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24336
24337#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24338/* XXX: split into separate functions for each field type? */
24339DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
24340 duk_hthread *thr;
24341 duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
24342 duk_small_int_t magic_ftype;
24343 duk_small_int_t magic_bigendian;
24344 duk_small_int_t magic_signed;
24345 duk_small_int_t magic_typedarray;
24346 duk_small_int_t endswap;
24347 duk_hbufferobject *h_this;
24348 duk_bool_t no_assert;
24349 duk_int_t offset_signed;
24350 duk_uint_t offset;
24351 duk_uint_t buffer_length;
24352 duk_uint_t check_length;
24353 duk_uint8_t *buf;
24354 duk_double_union du;
24355 duk_int_t nbytes = 0;
24356
24357 thr = (duk_hthread *) ctx;
24358 DUK_UNREF(thr);
24359
24360 magic_ftype = magic & 0x0007;
24361 magic_bigendian = magic & 0x0008;
24362 magic_signed = magic & 0x0010;
24363 magic_typedarray = magic & 0x0020;
24364 DUK_UNREF(magic_signed);
24365
24366 h_this = duk__require_bufobj_this(ctx);
24367 DUK_ASSERT(h_this != NULL);
24368 buffer_length = h_this->length;
24369
24370 /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */
24371 /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
24372 /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
24373
24374 /* Handle TypedArray vs. Node.js Buffer arg differences */
24375 if (magic_typedarray) {
24376 no_assert = 0;
24377#if defined(DUK_USE_INTEGER_LE)
24378 endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */
24379#else
24380 endswap = duk_to_boolean(ctx, 2); /* 1=little endian */
24381#endif
24382 duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */
24383 } else {
24384 no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
24385#if defined(DUK_USE_INTEGER_LE)
24386 endswap = magic_bigendian;
24387#else
24388 endswap = !magic_bigendian;
24389#endif
24390 }
24391
24392 /* Offset is coerced first to signed integer range and then to unsigned.
24393 * This ensures we can add a small byte length (1-8) to the offset in
24394 * bound checks and not wrap.
24395 */
24396 offset_signed = duk_to_int(ctx, 1);
24397 offset = (duk_uint_t) offset_signed;
24398
24399 /* We need 'nbytes' even for a failed offset; return value must be
24400 * (offset + nbytes) even when write fails due to invalid offset.
24401 */
24402 if (magic_ftype != DUK__FLD_VARINT) {
24403 DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
24404 nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
24405 } else {
24406 nbytes = duk_get_int(ctx, 2);
24407 if (nbytes < 1 || nbytes > 6) {
24408 goto fail_field_length;
24409 }
24410 }
24411 DUK_ASSERT(nbytes >= 1 && nbytes <= 8);
24412
24413 /* Now we can check offset validity. */
24414 if (offset_signed < 0) {
24415 goto fail_bounds;
24416 }
24417
24418 DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
24419 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
24420 "endswap=%d",
24421 duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert,
24422 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
24423 (int) (magic_signed >> 4), (int) endswap));
24424
24425 /* Coerce value to a number before computing check_length, so that
24426 * the field type specific coercion below can't have side effects
24427 * that would invalidate check_length.
24428 */
24429 duk_to_number(ctx, 0);
24430
24431 /* Update 'buffer_length' to be the effective, safe limit which
24432 * takes into account the underlying buffer. This value will be
24433 * potentially invalidated by any side effect.
24434 */
24435 check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
24436 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
24437 (long) buffer_length, (long) check_length));
24438
24439 if (h_this->buf) {
24440 buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
24441 } else {
24442 /* Neutered. We could go into the switch-case safely with
24443 * buf == NULL because check_length == 0. To avoid scanbuild
24444 * warnings, fail directly instead.
24445 */
24446 DUK_ASSERT(check_length == 0);
24447 goto fail_neutered;
24448 }
24449 DUK_ASSERT(buf != NULL);
24450
24451 switch (magic_ftype) {
24452 case DUK__FLD_8BIT: {
24453 if (offset + 1U > check_length) {
24454 goto fail_bounds;
24455 }
24456 /* sign doesn't matter when writing */
24457 buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0);
24458 break;
24459 }
24460 case DUK__FLD_16BIT: {
24461 duk_uint16_t tmp;
24462 if (offset + 2U > check_length) {
24463 goto fail_bounds;
24464 }
24465 tmp = (duk_uint16_t) duk_to_uint32(ctx, 0);
24466 if (endswap) {
24467 tmp = DUK_BSWAP16(tmp);
24468 }
24469 du.us[0] = tmp;
24470 /* sign doesn't matter when writing */
24471 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2);
24472 break;
24473 }
24474 case DUK__FLD_32BIT: {
24475 duk_uint32_t tmp;
24476 if (offset + 4U > check_length) {
24477 goto fail_bounds;
24478 }
24479 tmp = (duk_uint32_t) duk_to_uint32(ctx, 0);
24480 if (endswap) {
24481 tmp = DUK_BSWAP32(tmp);
24482 }
24483 du.ui[0] = tmp;
24484 /* sign doesn't matter when writing */
24485 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
24486 break;
24487 }
24488 case DUK__FLD_FLOAT: {
24489 duk_uint32_t tmp;
24490 if (offset + 4U > check_length) {
24491 goto fail_bounds;
24492 }
24493 du.f[0] = (duk_float_t) duk_to_number(ctx, 0);
24494 if (endswap) {
24495 tmp = du.ui[0];
24496 tmp = DUK_BSWAP32(tmp);
24497 du.ui[0] = tmp;
24498 }
24499 /* sign doesn't matter when writing */
24500 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
24501 break;
24502 }
24503 case DUK__FLD_DOUBLE: {
24504 if (offset + 8U > check_length) {
24505 goto fail_bounds;
24506 }
24507 du.d = (duk_double_t) duk_to_number(ctx, 0);
24508 if (endswap) {
24509 DUK_DBLUNION_BSWAP64(&du);
24510 }
24511 /* sign doesn't matter when writing */
24512 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8);
24513 break;
24514 }
24515 case DUK__FLD_VARINT: {
24516 /* Node.js Buffer variable width integer field. We don't really
24517 * care about speed here, so aim for shortest algorithm.
24518 */
24519 duk_int_t field_bytelen;
24520 duk_int_t i, i_step, i_end;
24521#if defined(DUK_USE_64BIT_OPS)
24522 duk_int64_t tmp;
24523#else
24524 duk_double_t tmp;
24525#endif
24526 duk_uint8_t *p;
24527
24528 field_bytelen = (duk_int_t) nbytes;
24529 if (offset + (duk_uint_t) field_bytelen > check_length) {
24530 goto fail_bounds;
24531 }
24532
24533 /* Slow writing of value using either 64-bit arithmetic
24534 * or IEEE doubles if 64-bit types not available. There's
24535 * no special sign handling when writing varints.
24536 */
24537
24538 if (magic_bigendian) {
24539 /* Write in big endian */
24540 i = field_bytelen; /* one i_step added at top of loop */
24541 i_step = -1;
24542 i_end = 0;
24543 } else {
24544 /* Write in little endian */
24545 i = -1; /* one i_step added at top of loop */
24546 i_step = 1;
24547 i_end = field_bytelen - 1;
24548 }
24549
24550 /* XXX: The duk_to_number() cast followed by integer coercion
24551 * is platform specific so NaN, +/- Infinity, and out-of-bounds
24552 * values result in platform specific output now.
24553 * See: test-bi-nodejs-buffer-proto-varint-special.js
24554 */
24555
24556#if defined(DUK_USE_64BIT_OPS)
24557 tmp = (duk_int64_t) duk_to_number(ctx, 0);
24558 p = (duk_uint8_t *) (buf + offset);
24559 do {
24560 i += i_step;
24561 DUK_ASSERT(i >= 0 && i < field_bytelen);
24562 p[i] = (duk_uint8_t) (tmp & 0xff);
24563 tmp = tmp >> 8; /* unnecessary shift for last byte */
24564 } while (i != i_end);
24565#else
24566 tmp = duk_to_number(ctx, 0);
24567 p = (duk_uint8_t *) (buf + offset);
24568 do {
24569 i += i_step;
24570 tmp = DUK_FLOOR(tmp);
24571 DUK_ASSERT(i >= 0 && i < field_bytelen);
24572 p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0));
24573 tmp = tmp / 256.0; /* unnecessary div for last byte */
24574 } while (i != i_end);
24575#endif
24576 break;
24577 }
24578 default: { /* should never happen but default here */
24579 goto fail_bounds;
24580 }
24581 }
24582
24583 /* Node.js Buffer: return offset + #bytes written (i.e. next
24584 * write offset).
24585 */
24586 if (magic_typedarray) {
24587 /* For TypedArrays 'undefined' return value is specified
24588 * by ES6 (matches V8).
24589 */
24590 return 0;
24591 }
24592 duk_push_uint(ctx, offset + nbytes);
24593 return 1;
24594
24595 fail_neutered:
24596 fail_field_length:
24597 fail_bounds:
24598 if (no_assert) {
24599 /* Node.js return value for failed writes is offset + #bytes
24600 * that would have been written.
24601 */
24602 /* XXX: for negative input offsets, 'offset' will be a large
24603 * positive value so the result here is confusing.
24604 */
24605 if (magic_typedarray) {
24606 return 0;
24607 }
24608 duk_push_uint(ctx, offset + nbytes);
24609 return 1;
24610 }
24611 return DUK_RET_RANGE_ERROR;
24612}
24613#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
24614DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
24615 DUK_UNREF(ctx);
24616 return DUK_RET_UNSUPPORTED_ERROR;
24617}
24618#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24619
24620#undef DUK__FLD_8BIT
24621#undef DUK__FLD_16BIT
24622#undef DUK__FLD_32BIT
24623#undef DUK__FLD_FLOAT
24624#undef DUK__FLD_DOUBLE
24625#undef DUK__FLD_VARINT
24626#undef DUK__FLD_BIGENDIAN
24627#undef DUK__FLD_SIGNED
24628#undef DUK__FLD_TYPEDARRAY
24629#line 1 "duk_bi_date.c"
24630/*
24631 * Date built-ins
24632 *
24633 * Unlike most built-ins, Date has some platform dependencies for getting
24634 * UTC time, converting between UTC and local time, and parsing and
24635 * formatting time values. These are all abstracted behind DUK_USE_xxx
24636 * config options. There are built-in platform specific providers for
24637 * POSIX and Windows, but external providers can also be used.
24638 *
24639 * See doc/datetime.rst.
24640 *
24641 */
24642
24643/* include removed: duk_internal.h */
24644
24645/*
24646 * Forward declarations
24647 */
24648
24649DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
24650DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags);
24651DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val);
24652DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags);
24653
24654/*
24655 * Other file level defines
24656 */
24657
24658/* Debug macro to print all parts and dparts (used manually because of debug level). */
24659#define DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts) do { \
24660 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
24661 (long) (parts)[0], (long) (parts)[1], \
24662 (long) (parts)[2], (long) (parts)[3], \
24663 (long) (parts)[4], (long) (parts)[5], \
24664 (long) (parts)[6], (long) (parts)[7], \
24665 (double) (dparts)[0], (double) (dparts)[1], \
24666 (double) (dparts)[2], (double) (dparts)[3], \
24667 (double) (dparts)[4], (double) (dparts)[5], \
24668 (double) (dparts)[6], (double) (dparts)[7])); \
24669 } while (0)
24670#define DUK__DPRINT_PARTS(parts) do { \
24671 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \
24672 (long) (parts)[0], (long) (parts)[1], \
24673 (long) (parts)[2], (long) (parts)[3], \
24674 (long) (parts)[4], (long) (parts)[5], \
24675 (long) (parts)[6], (long) (parts)[7])); \
24676 } while (0)
24677#define DUK__DPRINT_DPARTS(dparts) do { \
24678 DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
24679 (double) (dparts)[0], (double) (dparts)[1], \
24680 (double) (dparts)[2], (double) (dparts)[3], \
24681 (double) (dparts)[4], (double) (dparts)[5], \
24682 (double) (dparts)[6], (double) (dparts)[7])); \
24683 } while (0)
24684
24685/* Equivalent year for DST calculations outside [1970,2038[ range, see
24686 * E5 Section 15.9.1.8. Equivalent year has the same leap-year-ness and
24687 * starts with the same weekday on Jan 1.
24688 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
24689 */
24690#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
24691DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
24692#if 1
24693 /* This is based on V8 EquivalentYear() algorithm (see src/genequivyear.py):
24694 * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
24695 */
24696
24697 /* non-leap year: sunday, monday, ... */
24698 DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031),
24699 DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011),
24700
24701 /* leap year: sunday, monday, ... */
24702 DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020),
24703 DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028)
24704#endif
24705
24706#if 0
24707 /* This is based on Rhino EquivalentYear() algorithm:
24708 * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java
24709 */
24710
24711 /* non-leap year: sunday, monday, ... */
24712 DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986),
24713 DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977),
24714
24715 /* leap year: sunday, monday, ... */
24716 DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992),
24717 DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
24718#endif
24719};
24720#undef DUK__YEAR
24721
24722/*
24723 * ISO 8601 subset parser.
24724 */
24725
24726/* Parser part count. */
24727#define DUK__NUM_ISO8601_PARSER_PARTS 9
24728
24729/* Parser part indices. */
24730#define DUK__PI_YEAR 0
24731#define DUK__PI_MONTH 1
24732#define DUK__PI_DAY 2
24733#define DUK__PI_HOUR 3
24734#define DUK__PI_MINUTE 4
24735#define DUK__PI_SECOND 5
24736#define DUK__PI_MILLISECOND 6
24737#define DUK__PI_TZHOUR 7
24738#define DUK__PI_TZMINUTE 8
24739
24740/* Parser part masks. */
24741#define DUK__PM_YEAR (1 << DUK__PI_YEAR)
24742#define DUK__PM_MONTH (1 << DUK__PI_MONTH)
24743#define DUK__PM_DAY (1 << DUK__PI_DAY)
24744#define DUK__PM_HOUR (1 << DUK__PI_HOUR)
24745#define DUK__PM_MINUTE (1 << DUK__PI_MINUTE)
24746#define DUK__PM_SECOND (1 << DUK__PI_SECOND)
24747#define DUK__PM_MILLISECOND (1 << DUK__PI_MILLISECOND)
24748#define DUK__PM_TZHOUR (1 << DUK__PI_TZHOUR)
24749#define DUK__PM_TZMINUTE (1 << DUK__PI_TZMINUTE)
24750
24751/* Parser separator indices. */
24752#define DUK__SI_PLUS 0
24753#define DUK__SI_MINUS 1
24754#define DUK__SI_T 2
24755#define DUK__SI_SPACE 3
24756#define DUK__SI_COLON 4
24757#define DUK__SI_PERIOD 5
24758#define DUK__SI_Z 6
24759#define DUK__SI_NUL 7
24760
24761/* Parser separator masks. */
24762#define DUK__SM_PLUS (1 << DUK__SI_PLUS)
24763#define DUK__SM_MINUS (1 << DUK__SI_MINUS)
24764#define DUK__SM_T (1 << DUK__SI_T)
24765#define DUK__SM_SPACE (1 << DUK__SI_SPACE)
24766#define DUK__SM_COLON (1 << DUK__SI_COLON)
24767#define DUK__SM_PERIOD (1 << DUK__SI_PERIOD)
24768#define DUK__SM_Z (1 << DUK__SI_Z)
24769#define DUK__SM_NUL (1 << DUK__SI_NUL)
24770
24771/* Rule control flags. */
24772#define DUK__CF_NEG (1 << 0) /* continue matching, set neg_tzoffset flag */
24773#define DUK__CF_ACCEPT (1 << 1) /* accept string */
24774#define DUK__CF_ACCEPT_NUL (1 << 2) /* accept string if next char is NUL (otherwise reject) */
24775
24776#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags) \
24777 ((duk_uint32_t) (partmask) + \
24778 (((duk_uint32_t) (sepmask)) << 9) + \
24779 (((duk_uint32_t) (nextpart)) << 17) + \
24780 (((duk_uint32_t) (flags)) << 21))
24781
24782#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags) do { \
24783 (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \
24784 (var_flags) = (duk_small_uint_t) ((rule) >> 21); \
24785 } while (0)
24786
24787#define DUK__RULE_MASK_PART_SEP 0x1ffffUL
24788
24789/* Matching separator index is used in the control table */
24790DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = {
24791 DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/,
24792 DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/
24793};
24794
24795/* Rule table: first matching rule is used to determine what to do next. */
24796DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
24797 DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
24798 DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
24799 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0),
24800 DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
24801 DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
24802 DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
24803 DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
24804 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),
24805 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),
24806 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),
24807 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)
24808
24809 /* Note1: the specification doesn't require matching a time form with
24810 * just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z".
24811 *
24812 * Note2: the specification doesn't require matching a timezone offset
24813 * with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02"
24814 */
24815};
24816
24817DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
24818 duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
24819 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
24820 duk_double_t d;
24821 const duk_uint8_t *p;
24822 duk_small_uint_t part_idx = 0;
24823 duk_int_t accum = 0;
24824 duk_small_uint_t ndigits = 0;
24825 duk_bool_t neg_year = 0;
24826 duk_bool_t neg_tzoffset = 0;
24827 duk_uint_fast8_t ch;
24828 duk_small_uint_t i;
24829
24830 /* During parsing, month and day are one-based; set defaults here. */
24831 DUK_MEMZERO(parts, sizeof(parts));
24832 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */
24833 parts[DUK_DATE_IDX_MONTH] = 1;
24834 parts[DUK_DATE_IDX_DAY] = 1;
24835
24836 /* Special handling for year sign. */
24837 p = (const duk_uint8_t *) str;
24838 ch = p[0];
24839 if (ch == DUK_ASC_PLUS) {
24840 p++;
24841 } else if (ch == DUK_ASC_MINUS) {
24842 neg_year = 1;
24843 p++;
24844 }
24845
24846 for (;;) {
24847 ch = *p++;
24848 DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')",
24849 (long) part_idx, (long) ch,
24850 (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION)));
24851
24852 if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) {
24853 if (ndigits >= 9) {
24854 DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
24855 goto reject;
24856 }
24857 if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits >= 3) {
24858 /* ignore millisecond fractions after 3 */
24859 } else {
24860 accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
24861 ndigits++;
24862 }
24863 } else {
24864 duk_uint_fast32_t match_val;
24865 duk_small_int_t sep_idx;
24866
24867 if (ndigits <= 0) {
24868 goto reject;
24869 }
24870 if (part_idx == DUK__PI_MILLISECOND) {
24871 /* complete the millisecond field */
24872 while (ndigits < 3) {
24873 accum *= 10;
24874 ndigits++;
24875 }
24876 }
24877 parts[part_idx] = accum;
24878 DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", (long) part_idx, (long) accum));
24879
24880 accum = 0;
24881 ndigits = 0;
24882
24883 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) {
24884 if (duk__parse_iso8601_seps[i] == ch) {
24885 break;
24886 }
24887 }
24888 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) {
24889 DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject"));
24890 goto reject;
24891 }
24892
24893 sep_idx = i;
24894 match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); /* match against rule part/sep bits */
24895
24896 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) {
24897 duk_uint_fast32_t rule = duk__parse_iso8601_control[i];
24898 duk_small_uint_t nextpart;
24899 duk_small_uint_t cflags;
24900
24901 DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx",
24902 (long) part_idx, (long) sep_idx,
24903 (unsigned long) match_val, (unsigned long) rule));
24904
24905 if ((rule & match_val) != match_val) {
24906 continue;
24907 }
24908
24909 DUK__UNPACK_RULE(rule, nextpart, cflags);
24910
24911 DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, "
24912 "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx",
24913 (long) part_idx, (long) sep_idx,
24914 (unsigned long) match_val, (unsigned long) rule,
24915 (long) nextpart, (unsigned long) cflags));
24916
24917 if (cflags & DUK__CF_NEG) {
24918 neg_tzoffset = 1;
24919 }
24920
24921 if (cflags & DUK__CF_ACCEPT) {
24922 goto accept;
24923 }
24924
24925 if (cflags & DUK__CF_ACCEPT_NUL) {
24926 DUK_ASSERT(*(p - 1) != (char) 0);
24927 if (*p == DUK_ASC_NUL) {
24928 goto accept;
24929 }
24930 goto reject;
24931 }
24932
24933 part_idx = nextpart;
24934 break;
24935 } /* rule match */
24936
24937 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) {
24938 DUK_DDD(DUK_DDDPRINT("no rule matches -> reject"));
24939 goto reject;
24940 }
24941
24942 if (ch == 0) {
24943 /* This shouldn't be necessary, but check just in case
24944 * to avoid any chance of overruns.
24945 */
24946 DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject"));
24947 goto reject;
24948 }
24949 } /* if-digit-else-ctrl */
24950 } /* char loop */
24951
24952 /* We should never exit the loop above. */
24953 DUK_UNREACHABLE();
24954
24955 reject:
24956 DUK_DDD(DUK_DDDPRINT("reject"));
24957 return 0;
24958
24959 accept:
24960 DUK_DDD(DUK_DDDPRINT("accept"));
24961
24962 /* Apply timezone offset to get the main parts in UTC */
24963 if (neg_year) {
24964 parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
24965 }
24966 if (neg_tzoffset) {
24967 parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
24968 parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
24969 } else {
24970 parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
24971 parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
24972 }
24973 parts[DUK__PI_MONTH] -= 1; /* zero-based month */
24974 parts[DUK__PI_DAY] -= 1; /* zero-based day */
24975
24976 /* Use double parts, they tolerate unnormalized time.
24977 *
24978 * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR)
24979 * on purpose. It won't be actually used by duk_bi_date_get_timeval_from_dparts(),
24980 * but will make the value initialized just in case, and avoid any
24981 * potential for Valgrind issues.
24982 */
24983 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
24984 DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) parts[i]));
24985 dparts[i] = parts[i];
24986 }
24987
24988 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
24989 duk_push_number(ctx, d);
24990 return 1;
24991}
24992
24993/*
24994 * Date/time parsing helper.
24995 *
24996 * Parse a datetime string into a time value. We must first try to parse
24997 * the input according to the standard format in E5.1 Section 15.9.1.15.
24998 * If that fails, we can try to parse using custom parsing, which can
24999 * either be platform neutral (custom code) or platform specific (using
25000 * existing platform API calls).
25001 *
25002 * Note in particular that we must parse whatever toString(), toUTCString(),
25003 * and toISOString() can produce; see E5.1 Section 15.9.4.2.
25004 *
25005 * Returns 1 to allow tail calling.
25006 *
25007 * There is much room for improvement here with respect to supporting
25008 * alternative datetime formats. For instance, V8 parses '2012-01-01' as
25009 * UTC and '2012/01/01' as local time.
25010 */
25011
25012DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
25013 /* XXX: there is a small risk here: because the ISO 8601 parser is
25014 * very loose, it may end up parsing some datetime values which
25015 * would be better parsed with a platform specific parser.
25016 */
25017
25018 DUK_ASSERT(str != NULL);
25019 DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
25020
25021 if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
25022 return 1;
25023 }
25024
25025#if defined(DUK_USE_DATE_PARSE_STRING)
25026 /* Contract, either:
25027 * - Push value on stack and return 1
25028 * - Don't push anything on stack and return 0
25029 */
25030
25031 if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
25032 return 1;
25033 }
25034#else
25035 /* No platform-specific parsing, this is not an error. */
25036#endif
25037
25038 duk_push_nan(ctx);
25039 return 1;
25040}
25041
25042/*
25043 * Calendar helpers
25044 *
25045 * Some helpers are used for getters and can operate on normalized values
25046 * which can be represented with 32-bit signed integers. Other helpers are
25047 * needed by setters and operate on un-normalized double values, must watch
25048 * out for non-finite numbers etc.
25049 */
25050
25051DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
25052 (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30,
25053 (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31,
25054 (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31
25055};
25056
25057/* Maximum iteration count for computing UTC-to-local time offset when
25058 * creating an Ecmascript time value from local parts.
25059 */
25060#define DUK__LOCAL_TZOFFSET_MAXITER 4
25061
25062/* Because 'day since epoch' can be negative and is used to compute weekday
25063 * using a modulo operation, add this multiple of 7 to avoid negative values
25064 * when year is below 1970 epoch. Ecmascript time values are restricted to
25065 * +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
25066 * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
25067 */
25068#define DUK__WEEKDAY_MOD_ADDER (20000000 * 7) /* 0x08583b00 */
25069
25070DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) {
25071 if ((year % 4) != 0) {
25072 return 0;
25073 }
25074 if ((year % 100) != 0) {
25075 return 1;
25076 }
25077 if ((year % 400) != 0) {
25078 return 0;
25079 }
25080 return 1;
25081}
25082
25083DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) {
25084 return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS);
25085}
25086
25087DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) {
25088 return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY);
25089}
25090
25091DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) {
25092 return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR);
25093}
25094
25095DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) {
25096 if (!DUK_ISFINITE(x)) {
25097 return DUK_DOUBLE_NAN;
25098 }
25099
25100 if (!duk_bi_date_timeval_in_valid_range(x)) {
25101 return DUK_DOUBLE_NAN;
25102 }
25103
25104 x = duk_js_tointeger_number(x);
25105
25106 /* Here we'd have the option to normalize -0 to +0. */
25107 return x;
25108}
25109
25110/* Integer division which floors also negative values correctly. */
25111DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) {
25112 DUK_ASSERT(b > 0);
25113 if (a >= 0) {
25114 return a / b;
25115 } else {
25116 /* e.g. a = -4, b = 5 --> -4 - 5 + 1 / 5 --> -8 / 5 --> -1
25117 * a = -5, b = 5 --> -5 - 5 + 1 / 5 --> -9 / 5 --> -1
25118 * a = -6, b = 5 --> -6 - 5 + 1 / 5 --> -10 / 5 --> -2
25119 */
25120 return (a - b + 1) / b;
25121 }
25122}
25123
25124/* Compute day number of the first day of a given year. */
25125DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) {
25126 /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative
25127 * values, but is incorrect for negative ones.
25128 */
25129 return 365 * (year - 1970)
25130 + duk__div_floor(year - 1969, 4)
25131 - duk__div_floor(year - 1901, 100)
25132 + duk__div_floor(year - 1601, 400);
25133}
25134
25135/* Given a day number, determine year and day-within-year. */
25136DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) {
25137 duk_int_t year;
25138 duk_int_t diff_days;
25139
25140 /* estimate year upwards (towards positive infinity), then back down;
25141 * two iterations should be enough
25142 */
25143
25144 if (day >= 0) {
25145 year = 1970 + day / 365;
25146 } else {
25147 year = 1970 + day / 366;
25148 }
25149
25150 for (;;) {
25151 diff_days = duk__day_from_year(year) - day;
25152 DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) year, (long) day, (long) diff_days));
25153 if (diff_days <= 0) {
25154 DUK_ASSERT(-diff_days < 366); /* fits into duk_small_int_t */
25155 *out_day_within_year = -diff_days;
25156 DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld",
25157 (long) year, (long) *out_day_within_year));
25158 DUK_ASSERT(*out_day_within_year >= 0);
25159 DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365));
25160 return year;
25161 }
25162
25163 /* Note: this is very tricky; we must never 'overshoot' the
25164 * correction downwards.
25165 */
25166 year -= 1 + (diff_days - 1) / 366; /* conservative */
25167 }
25168}
25169
25170/* Given a (year, month, day-within-month) triple, compute day number.
25171 * The input triple is un-normalized and may contain non-finite values.
25172 */
25173DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) {
25174 duk_int_t day_num;
25175 duk_bool_t is_leap;
25176 duk_small_int_t i, n;
25177
25178 /* Assume that year, month, day are all coerced to whole numbers.
25179 * They may also be NaN or infinity, in which case this function
25180 * must return NaN or infinity to ensure time value becomes NaN.
25181 * If 'day' is NaN, the final return will end up returning a NaN,
25182 * so it doesn't need to be checked here.
25183 */
25184
25185 if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
25186 return DUK_DOUBLE_NAN;
25187 }
25188
25189 year += DUK_FLOOR(month / 12.0);
25190
25191 month = DUK_FMOD(month, 12.0);
25192 if (month < 0.0) {
25193 /* handle negative values */
25194 month += 12.0;
25195 }
25196
25197 /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
25198 * does not normalize the day-of-month (nor check whether or not
25199 * it is finite) because it's not necessary for finding the day
25200 * number which matches the (year,month) pair.
25201 *
25202 * We assume that duk__day_from_year() is exact here.
25203 *
25204 * Without an explicit infinity / NaN check in the beginning,
25205 * day_num would be a bogus integer here.
25206 *
25207 * It's possible for 'year' to be out of integer range here.
25208 * If so, we need to return NaN without integer overflow.
25209 * This fixes test-bug-setyear-overflow.js.
25210 */
25211
25212 if (!duk_bi_date_year_in_valid_range(year)) {
25213 DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf", (double) year));
25214 return DUK_DOUBLE_NAN;
25215 }
25216 day_num = duk__day_from_year((duk_int_t) year);
25217 is_leap = duk_bi_date_is_leap_year((duk_int_t) year);
25218
25219 n = (duk_small_int_t) month;
25220 for (i = 0; i < n; i++) {
25221 day_num += duk__days_in_month[i];
25222 if (i == 1 && is_leap) {
25223 day_num++;
25224 }
25225 }
25226
25227 /* If 'day' is NaN, returns NaN. */
25228 return (duk_double_t) day_num + day;
25229}
25230
25231/* Split time value into parts. The time value is assumed to be an internal
25232 * one, i.e. finite, no fractions. Possible local time adjustment has already
25233 * been applied when reading the time value.
25234 */
25235DUK_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) {
25236 duk_double_t d1, d2;
25237 duk_int_t t1, t2;
25238 duk_int_t day_since_epoch;
25239 duk_int_t year; /* does not fit into 16 bits */
25240 duk_small_int_t day_in_year;
25241 duk_small_int_t month;
25242 duk_small_int_t day;
25243 duk_small_int_t dim;
25244 duk_int_t jan1_since_epoch;
25245 duk_small_int_t jan1_weekday;
25246 duk_int_t equiv_year;
25247 duk_small_uint_t i;
25248 duk_bool_t is_leap;
25249 duk_small_int_t arridx;
25250
25251 DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
25252 DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
25253
25254 /* The timevalue must be in valid Ecmascript range, but since a local
25255 * time offset can be applied, we need to allow a +/- 24h leeway to
25256 * the value. In other words, although the UTC time is within the
25257 * Ecmascript range, the local part values can be just outside of it.
25258 */
25259 DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
25260 DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
25261
25262 /* these computations are guaranteed to be exact for the valid
25263 * E5 time value range, assuming milliseconds without fractions.
25264 */
25265 d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
25266 if (d1 < 0.0) {
25267 /* deal with negative values */
25268 d1 += (duk_double_t) DUK_DATE_MSEC_DAY;
25269 }
25270 d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
25271 DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d);
25272 /* now expected to fit into a 32-bit integer */
25273 t1 = (duk_int_t) d1;
25274 t2 = (duk_int_t) d2;
25275 day_since_epoch = t2;
25276 DUK_ASSERT((duk_double_t) t1 == d1);
25277 DUK_ASSERT((duk_double_t) t2 == d2);
25278
25279 /* t1 = milliseconds within day (fits 32 bit)
25280 * t2 = day number from epoch (fits 32 bit, may be negative)
25281 */
25282
25283 parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
25284 parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
25285 parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
25286 parts[DUK_DATE_IDX_HOUR] = t1;
25287 DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999);
25288 DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59);
25289 DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59);
25290 DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23);
25291
25292 DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld",
25293 (double) d, (double) d1, (double) d2, (long) t1, (long) t2,
25294 (long) parts[DUK_DATE_IDX_HOUR],
25295 (long) parts[DUK_DATE_IDX_MINUTE],
25296 (long) parts[DUK_DATE_IDX_SECOND],
25297 (long) parts[DUK_DATE_IDX_MILLISECOND]));
25298
25299 /* This assert depends on the input parts representing time inside
25300 * the Ecmascript range.
25301 */
25302 DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
25303 parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
25304 DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6);
25305
25306 year = duk__year_from_day(t2, &day_in_year);
25307 day = day_in_year;
25308 is_leap = duk_bi_date_is_leap_year(year);
25309 for (month = 0; month < 12; month++) {
25310 dim = duk__days_in_month[month];
25311 if (month == 1 && is_leap) {
25312 dim++;
25313 }
25314 DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
25315 (long) month, (long) dim, (long) day));
25316 if (day < dim) {
25317 break;
25318 }
25319 day -= dim;
25320 }
25321 DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
25322 DUK_ASSERT(month >= 0 && month <= 11);
25323 DUK_ASSERT(day >= 0 && day <= 31);
25324
25325 /* Equivalent year mapping, used to avoid DST trouble when platform
25326 * may fail to provide reasonable DST answers for dates outside the
25327 * ordinary range (e.g. 1970-2038). An equivalent year has the same
25328 * leap-year-ness as the original year and begins on the same weekday
25329 * (Jan 1).
25330 *
25331 * The year 2038 is avoided because there seem to be problems with it
25332 * on some platforms. The year 1970 is also avoided as there were
25333 * practical problems with it; an equivalent year is used for it too,
25334 * which breaks some DST computations for 1970 right now, see e.g.
25335 * test-bi-date-tzoffset-brute-fi.js.
25336 */
25337 if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
25338 DUK_ASSERT(is_leap == 0 || is_leap == 1);
25339
25340 jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */
25341 DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
25342 jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
25343 DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
25344 arridx = jan1_weekday;
25345 if (is_leap) {
25346 arridx += 7;
25347 }
25348 DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
25349
25350 equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
25351 year = equiv_year;
25352 DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, "
25353 "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld",
25354 (long) year, (long) day_in_year, (long) day_since_epoch,
25355 (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year));
25356 }
25357
25358 parts[DUK_DATE_IDX_YEAR] = year;
25359 parts[DUK_DATE_IDX_MONTH] = month;
25360 parts[DUK_DATE_IDX_DAY] = day;
25361
25362 if (flags & DUK_DATE_FLAG_ONEBASED) {
25363 parts[DUK_DATE_IDX_MONTH]++; /* zero-based -> one-based */
25364 parts[DUK_DATE_IDX_DAY]++; /* -""- */
25365 }
25366
25367 if (dparts != NULL) {
25368 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
25369 dparts[i] = (duk_double_t) parts[i];
25370 }
25371 }
25372}
25373
25374/* Compute time value from (double) parts. The parts can be either UTC
25375 * or local time; if local, they need to be (conceptually) converted into
25376 * UTC time. The parts may represent valid or invalid time, and may be
25377 * wildly out of range (but may cancel each other and still come out in
25378 * the valid Date range).
25379 */
25380DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) {
25381#if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
25382 /* See comments below on MakeTime why these are volatile. */
25383 volatile duk_double_t tmp_time;
25384 volatile duk_double_t tmp_day;
25385 volatile duk_double_t d;
25386#else
25387 duk_double_t tmp_time;
25388 duk_double_t tmp_day;
25389 duk_double_t d;
25390#endif
25391 duk_small_uint_t i;
25392 duk_int_t tzoff, tzoffprev1, tzoffprev2;
25393
25394 /* Expects 'this' at top of stack on entry. */
25395
25396 /* Coerce all finite parts with ToInteger(). ToInteger() must not
25397 * be called for NaN/Infinity because it will convert e.g. NaN to
25398 * zero. If ToInteger() has already been called, this has no side
25399 * effects and is idempotent.
25400 *
25401 * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
25402 * issues if the value is uninitialized.
25403 */
25404 for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
25405 /* SCANBUILD: scan-build complains here about assigned value
25406 * being garbage or undefined. This is correct but operating
25407 * on undefined values has no ill effect and is ignored by the
25408 * caller in the case where this happens.
25409 */
25410 d = dparts[i];
25411 if (DUK_ISFINITE(d)) {
25412 dparts[i] = duk_js_tointeger_number(d);
25413 }
25414 }
25415
25416 /* Use explicit steps in computation to try to ensure that
25417 * computation happens with intermediate results coerced to
25418 * double values (instead of using something more accurate).
25419 * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
25420 * rules (= Ecmascript '+' and '*' operators).
25421 *
25422 * Without 'volatile' even this approach fails on some platform
25423 * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu
25424 * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
25425 * would fail because of some optimizations when computing tmp_time
25426 * (MakeTime below). Adding 'volatile' to tmp_time solved this
25427 * particular problem (annoyingly, also adding debug prints or
25428 * running the executable under valgrind hides it).
25429 */
25430
25431 /* MakeTime */
25432 tmp_time = 0.0;
25433 tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR);
25434 tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE);
25435 tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND);
25436 tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
25437
25438 /* MakeDay */
25439 tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
25440
25441 /* MakeDate */
25442 d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
25443
25444 DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
25445 (double) tmp_time, (double) tmp_day, (double) d));
25446
25447 /* Optional UTC conversion. */
25448 if (flags & DUK_DATE_FLAG_LOCALTIME) {
25449 /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
25450 * time value computed from UTC parts. At this point we only
25451 * have 'd' which is a time value computed from local parts, so
25452 * it is off by the UTC-to-local time offset which we don't know
25453 * yet. The current solution for computing the UTC-to-local
25454 * time offset is to iterate a few times and detect a fixed
25455 * point or a two-cycle loop (or a sanity iteration limit),
25456 * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js.
25457 *
25458 * E5.1 Section 15.9.1.9:
25459 * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
25460 *
25461 * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
25462 */
25463
25464#if 0
25465 /* Old solution: don't iterate, incorrect */
25466 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
25467 DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff));
25468 d -= tzoff * 1000L;
25469 DUK_UNREF(tzoffprev1);
25470 DUK_UNREF(tzoffprev2);
25471#endif
25472
25473 /* Iteration solution */
25474 tzoff = 0;
25475 tzoffprev1 = 999999999L; /* invalid value which never matches */
25476 for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
25477 tzoffprev2 = tzoffprev1;
25478 tzoffprev1 = tzoff;
25479 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L);
25480 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
25481 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25482 if (tzoff == tzoffprev1) {
25483 DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
25484 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25485 break;
25486 } else if (tzoff == tzoffprev2) {
25487 /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js.
25488 * In these cases, favor a higher tzoffset to get a consistent
25489 * result which is independent of iteration count. Not sure if
25490 * this is a generically correct solution.
25491 */
25492 DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
25493 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25494 if (tzoffprev1 > tzoff) {
25495 tzoff = tzoffprev1;
25496 }
25497 break;
25498 }
25499 }
25500 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) tzoff));
25501 d -= tzoff * 1000L;
25502 }
25503
25504 /* TimeClip(), which also handles Infinity -> NaN conversion */
25505 d = duk__timeclip(d);
25506
25507 return d;
25508}
25509
25510/*
25511 * API oriented helpers
25512 */
25513
25514/* Push 'this' binding, check that it is a Date object; then push the
25515 * internal time value. At the end, stack is: [ ... this timeval ].
25516 * Returns the time value. Local time adjustment is done if requested.
25517 */
25518DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
25519 duk_hthread *thr = (duk_hthread *) ctx;
25520 duk_hobject *h;
25521 duk_double_t d;
25522 duk_int_t tzoffset = 0;
25523
25524 duk_push_this(ctx);
25525 h = duk_get_hobject(ctx, -1); /* XXX: getter with class check, useful in built-ins */
25526 if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
25527 DUK_ERROR_TYPE(thr, "expected Date");
25528 }
25529
25530 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
25531 d = duk_to_number(ctx, -1);
25532 duk_pop(ctx);
25533
25534 if (DUK_ISNAN(d)) {
25535 if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
25536 d = 0.0;
25537 }
25538 if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
25539 DUK_ERROR_RANGE(thr, "Invalid Date");
25540 }
25541 }
25542 /* if no NaN handling flag, may still be NaN here, but not Inf */
25543 DUK_ASSERT(!DUK_ISINF(d));
25544
25545 if (flags & DUK_DATE_FLAG_LOCALTIME) {
25546 /* Note: DST adjustment is determined using UTC time.
25547 * If 'd' is NaN, tzoffset will be 0.
25548 */
25549 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); /* seconds */
25550 d += tzoffset * 1000L;
25551 }
25552 if (out_tzoffset) {
25553 *out_tzoffset = tzoffset;
25554 }
25555
25556 /* [ ... this ] */
25557 return d;
25558}
25559
25560DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags) {
25561 return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
25562}
25563
25564/* Set timeval to 'this' from dparts, push the new time value onto the
25565 * value stack and return 1 (caller can then tail call us). Expects
25566 * the value stack to contain 'this' on the stack top.
25567 */
25568DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags) {
25569 duk_double_t d;
25570
25571 /* [ ... this ] */
25572
25573 d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
25574 duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */
25575 duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */
25576 duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE);
25577
25578 /* stack top: new time value, return 1 to allow tail calls */
25579 return 1;
25580}
25581
25582/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
25583DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) {
25584 char yearstr[8]; /* "-123456\0" */
25585 char tzstr[8]; /* "+11:22\0" */
25586 char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE;
25587
25588 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
25589 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
25590 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999);
25591
25592 /* Note: %06d for positive value, %07d for negative value to include
25593 * sign and 6 digits.
25594 */
25595 DUK_SNPRINTF(yearstr,
25596 sizeof(yearstr),
25597 (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" :
25598 ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld"),
25599 (long) parts[DUK_DATE_IDX_YEAR]);
25600 yearstr[sizeof(yearstr) - 1] = (char) 0;
25601
25602 if (flags & DUK_DATE_FLAG_LOCALTIME) {
25603 /* tzoffset seconds are dropped; 16 bits suffice for
25604 * time offset in minutes
25605 */
25606 if (tzoffset >= 0) {
25607 duk_small_int_t tmp = tzoffset / 60;
25608 DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
25609 } else {
25610 duk_small_int_t tmp = -tzoffset / 60;
25611 DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
25612 }
25613 tzstr[sizeof(tzstr) - 1] = (char) 0;
25614 } else {
25615 tzstr[0] = DUK_ASC_UC_Z;
25616 tzstr[1] = (char) 0;
25617 }
25618
25619 /* Unlike year, the other parts fit into 16 bits so %d format
25620 * is portable.
25621 */
25622 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
25623 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
25624 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep,
25625 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
25626 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr);
25627 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
25628 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d",
25629 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]);
25630 } else {
25631 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
25632 DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s",
25633 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
25634 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND],
25635 (const char *) tzstr);
25636 }
25637}
25638
25639/* Helper for string conversion calls: check 'this' binding, get the
25640 * internal time value, and format date and/or time in a few formats.
25641 * Return value allows tail calls.
25642 */
25643DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t flags) {
25644 duk_double_t d;
25645 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25646 duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
25647 duk_bool_t rc;
25648 duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
25649
25650 DUK_UNREF(rc); /* unreferenced with some options */
25651
25652 d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
25653 if (DUK_ISNAN(d)) {
25654 duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
25655 return 1;
25656 }
25657 DUK_ASSERT(DUK_ISFINITE(d));
25658
25659 /* formatters always get one-based month/day-of-month */
25660 duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED);
25661 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
25662 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
25663
25664 if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) {
25665 /* try locale specific formatter; if it refuses to format the
25666 * string, fall back to an ISO 8601 formatted value in local
25667 * time.
25668 */
25669#if defined(DUK_USE_DATE_FORMAT_STRING)
25670 /* Contract, either:
25671 * - Push string to value stack and return 1
25672 * - Don't push anything and return 0
25673 */
25674
25675 rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
25676 if (rc != 0) {
25677 return 1;
25678 }
25679#else
25680 /* No locale specific formatter; this is OK, we fall back
25681 * to ISO 8601.
25682 */
25683#endif
25684 }
25685
25686 /* Different calling convention than above used because the helper
25687 * is shared.
25688 */
25689 duk__format_parts_iso8601(parts, tzoffset, flags, buf);
25690 duk_push_string(ctx, (const char *) buf);
25691 return 1;
25692}
25693
25694/* Helper for component getter calls: check 'this' binding, get the
25695 * internal time value, split it into parts (either as UTC time or
25696 * local time), push a specified component as a return value to the
25697 * value stack and return 1 (caller can then tail call us).
25698 */
25699DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flags_and_idx) {
25700 duk_double_t d;
25701 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25702 duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
25703
25704 DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
25705 DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
25706
25707 d = duk__push_this_get_timeval(ctx, flags_and_idx);
25708 if (DUK_ISNAN(d)) {
25709 duk_push_nan(ctx);
25710 return 1;
25711 }
25712 DUK_ASSERT(DUK_ISFINITE(d));
25713
25714 duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx); /* no need to mask idx portion */
25715
25716 /* Setter APIs detect special year numbers (0...99) and apply a +1900
25717 * only in certain cases. The legacy getYear() getter applies -1900
25718 * unconditionally.
25719 */
25720 duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
25721 return 1;
25722}
25723
25724/* Helper for component setter calls: check 'this' binding, get the
25725 * internal time value, split it into parts (either as UTC time or
25726 * local time), modify one or more components as specified, recompute
25727 * the time value, set it as the internal value. Finally, push the
25728 * new time value as a return value to the value stack and return 1
25729 * (caller can then tail call us).
25730 */
25731DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flags_and_maxnargs) {
25732 duk_double_t d;
25733 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25734 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
25735 duk_idx_t nargs;
25736 duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
25737 duk_small_uint_t idx_first, idx;
25738 duk_small_uint_t i;
25739
25740 nargs = duk_get_top(ctx);
25741 d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
25742 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
25743
25744 if (DUK_ISFINITE(d)) {
25745 duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs);
25746 } else {
25747 /* NaN timevalue: we need to coerce the arguments, but
25748 * the resulting internal timestamp needs to remain NaN.
25749 * This works but is not pretty: parts and dparts will
25750 * be partially uninitialized, but we only write to them.
25751 */
25752 }
25753
25754 /*
25755 * Determining which datetime components to overwrite based on
25756 * stack arguments is a bit complicated, but important to factor
25757 * out from setters themselves for compactness.
25758 *
25759 * If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type:
25760 *
25761 * 1 -> millisecond
25762 * 2 -> second, [millisecond]
25763 * 3 -> minute, [second], [millisecond]
25764 * 4 -> hour, [minute], [second], [millisecond]
25765 *
25766 * Else:
25767 *
25768 * 1 -> date
25769 * 2 -> month, [date]
25770 * 3 -> year, [month], [date]
25771 *
25772 * By comparing nargs and maxnargs (and flags) we know which
25773 * components to override. We rely on part index ordering.
25774 */
25775
25776 if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) {
25777 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
25778 idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1);
25779 } else {
25780 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
25781 idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1);
25782 }
25783 DUK_ASSERT_DISABLE(idx_first >= 0); /* unsigned */
25784 DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS);
25785
25786 for (i = 0; i < maxnargs; i++) {
25787 if ((duk_idx_t) i >= nargs) {
25788 /* no argument given -> leave components untouched */
25789 break;
25790 }
25791 idx = idx_first + i;
25792 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
25793 DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
25794
25795 if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
25796 duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
25797 }
25798
25799 dparts[idx] = duk_to_number(ctx, i);
25800
25801 if (idx == DUK_DATE_IDX_DAY) {
25802 /* Day-of-month is one-based in the API, but zero-based
25803 * internally, so fix here. Note that month is zero-based
25804 * both in the API and internally.
25805 */
25806 /* SCANBUILD: complains about use of uninitialized values.
25807 * The complaint is correct, but operating in undefined
25808 * values here is intentional in some cases and the caller
25809 * ignores the results.
25810 */
25811 dparts[idx] -= 1.0;
25812 }
25813 }
25814
25815 /* Leaves new timevalue on stack top and returns 1, which is correct
25816 * for part setters.
25817 */
25818 if (DUK_ISFINITE(d)) {
25819 return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
25820 } else {
25821 /* Internal timevalue is already NaN, so don't touch it. */
25822 duk_push_nan(ctx);
25823 return 1;
25824 }
25825}
25826
25827/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
25828 * 1900 and replace value at idx_val.
25829 */
25830DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
25831 duk_double_t d;
25832
25833 /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
25834 * might not generate better code due to casting.
25835 */
25836
25837 /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
25838 duk_to_number(ctx, idx_val);
25839 if (duk_is_nan(ctx, idx_val)) {
25840 return;
25841 }
25842 duk_dup(ctx, idx_val);
25843 duk_to_int(ctx, -1);
25844 d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */
25845 if (d >= 0.0 && d <= 99.0) {
25846 d += 1900.0;
25847 duk_push_number(ctx, d);
25848 duk_replace(ctx, idx_val);
25849 }
25850 duk_pop(ctx);
25851}
25852
25853/* Set datetime parts from stack arguments, defaulting any missing values.
25854 * Day-of-week is not set; it is not required when setting the time value.
25855 */
25856DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, duk_idx_t nargs) {
25857 duk_double_t d;
25858 duk_small_uint_t i;
25859 duk_small_uint_t idx;
25860
25861 /* Causes a ToNumber() coercion, but doesn't break coercion order since
25862 * year is coerced first anyway.
25863 */
25864 duk__twodigit_year_fixup(ctx, 0);
25865
25866 /* There are at most 7 args, but we use 8 here so that also
25867 * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
25868 * for any Valgrind gripes later.
25869 */
25870 for (i = 0; i < 8; i++) {
25871 /* Note: rely on index ordering */
25872 idx = DUK_DATE_IDX_YEAR + i;
25873 if ((duk_idx_t) i < nargs) {
25874 d = duk_to_number(ctx, (duk_idx_t) i);
25875 if (idx == DUK_DATE_IDX_DAY) {
25876 /* Convert day from one-based to zero-based (internal). This may
25877 * cause the day part to be negative, which is OK.
25878 */
25879 d -= 1.0;
25880 }
25881 } else {
25882 /* All components default to 0 except day-of-month which defaults
25883 * to 1. However, because our internal day-of-month is zero-based,
25884 * it also defaults to zero here.
25885 */
25886 d = 0.0;
25887 }
25888 dparts[idx] = d;
25889 }
25890
25891 DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf",
25892 (double) dparts[0], (double) dparts[1],
25893 (double) dparts[2], (double) dparts[3],
25894 (double) dparts[4], (double) dparts[5],
25895 (double) dparts[6], (double) dparts[7]));
25896}
25897
25898/*
25899 * Helper to format a time value into caller buffer, used by logging.
25900 * 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long.
25901 */
25902
25903DUK_INTERNAL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf) {
25904 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25905
25906 duk_bi_date_timeval_to_parts(timeval,
25907 parts,
25908 NULL,
25909 DUK_DATE_FLAG_ONEBASED);
25910
25911 duk__format_parts_iso8601(parts,
25912 0 /*tzoffset*/,
25913 DUK_DATE_FLAG_TOSTRING_DATE |
25914 DUK_DATE_FLAG_TOSTRING_TIME |
25915 DUK_DATE_FLAG_SEP_T /*flags*/,
25916 out_buf);
25917}
25918
25919/*
25920 * Indirect magic value lookup for Date methods.
25921 *
25922 * Date methods don't put their control flags into the function magic value
25923 * because they wouldn't fit into a LIGHTFUNC's magic field. Instead, the
25924 * magic value is set to an index pointing to the array of control flags
25925 * below.
25926 *
25927 * This must be kept in strict sync with genbuiltins.py!
25928 */
25929
25930static duk_uint16_t duk__date_magics[] = {
25931 /* 0: toString */
25932 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
25933
25934 /* 1: toDateString */
25935 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME,
25936
25937 /* 2: toTimeString */
25938 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
25939
25940 /* 3: toLocaleString */
25941 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
25942
25943 /* 4: toLocaleDateString */
25944 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
25945
25946 /* 5: toLocaleTimeString */
25947 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
25948
25949 /* 6: toUTCString */
25950 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME,
25951
25952 /* 7: toISOString */
25953 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T,
25954
25955 /* 8: getFullYear */
25956 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
25957
25958 /* 9: getUTCFullYear */
25959 0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
25960
25961 /* 10: getMonth */
25962 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
25963
25964 /* 11: getUTCMonth */
25965 0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
25966
25967 /* 12: getDate */
25968 DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
25969
25970 /* 13: getUTCDate */
25971 DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
25972
25973 /* 14: getDay */
25974 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
25975
25976 /* 15: getUTCDay */
25977 0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
25978
25979 /* 16: getHours */
25980 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
25981
25982 /* 17: getUTCHours */
25983 0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
25984
25985 /* 18: getMinutes */
25986 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
25987
25988 /* 19: getUTCMinutes */
25989 0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
25990
25991 /* 20: getSeconds */
25992 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
25993
25994 /* 21: getUTCSeconds */
25995 0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
25996
25997 /* 22: getMilliseconds */
25998 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
25999
26000 /* 23: getUTCMilliseconds */
26001 0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
26002
26003 /* 24: setMilliseconds */
26004 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
26005
26006 /* 25: setUTCMilliseconds */
26007 DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
26008
26009 /* 26: setSeconds */
26010 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
26011
26012 /* 27: setUTCSeconds */
26013 DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
26014
26015 /* 28: setMinutes */
26016 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
26017
26018 /* 29: setUTCMinutes */
26019 DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
26020
26021 /* 30: setHours */
26022 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
26023
26024 /* 31: setUTCHours */
26025 DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
26026
26027 /* 32: setDate */
26028 DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
26029
26030 /* 33: setUTCDate */
26031 0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
26032
26033 /* 34: setMonth */
26034 DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
26035
26036 /* 35: setUTCMonth */
26037 0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
26038
26039 /* 36: setFullYear */
26040 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
26041
26042 /* 37: setUTCFullYear */
26043 DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
26044
26045 /* 38: getYear */
26046 DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
26047
26048 /* 39: setYear */
26049 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
26050};
26051
26052DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
26053 duk_small_int_t magicidx = (duk_small_uint_t) duk_get_current_magic(ctx);
26054 DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
26055 return (duk_small_uint_t) duk__date_magics[magicidx];
26056}
26057
26058/*
26059 * Constructor calls
26060 */
26061
26062DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
26063 duk_idx_t nargs = duk_get_top(ctx);
26064 duk_bool_t is_cons = duk_is_constructor_call(ctx);
26065 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
26066 duk_double_t d;
26067
26068 DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
26069
26070 duk_push_object_helper(ctx,
26071 DUK_HOBJECT_FLAG_EXTENSIBLE |
26072 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
26073 DUK_BIDX_DATE_PROTOTYPE);
26074
26075 /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
26076 * is mutable.
26077 */
26078
26079 if (nargs == 0 || !is_cons) {
26080 d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
26081 duk_push_number(ctx, d);
26082 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
26083 if (!is_cons) {
26084 /* called as a normal function: return new Date().toString() */
26085 duk_to_string(ctx, -1);
26086 }
26087 return 1;
26088 } else if (nargs == 1) {
26089 duk_to_primitive(ctx, 0, DUK_HINT_NONE);
26090 if (duk_is_string(ctx, 0)) {
26091 duk__parse_string(ctx, duk_to_string(ctx, 0));
26092 duk_replace(ctx, 0); /* may be NaN */
26093 }
26094 d = duk__timeclip(duk_to_number(ctx, 0));
26095 duk_push_number(ctx, d);
26096 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
26097 return 1;
26098 }
26099
26100 duk__set_parts_from_args(ctx, dparts, nargs);
26101
26102 /* Parts are in local time, convert when setting. */
26103
26104 (void) duk__set_this_timeval_from_dparts(ctx, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
26105 duk_pop(ctx); /* -> [ ... this ] */
26106 return 1;
26107}
26108
26109DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
26110 return duk__parse_string(ctx, duk_to_string(ctx, 0));
26111}
26112
26113DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
26114 duk_idx_t nargs = duk_get_top(ctx);
26115 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
26116 duk_double_t d;
26117
26118 /* Behavior for nargs < 2 is implementation dependent: currently we'll
26119 * set a NaN time value (matching V8 behavior) in this case.
26120 */
26121
26122 if (nargs < 2) {
26123 duk_push_nan(ctx);
26124 } else {
26125 duk__set_parts_from_args(ctx, dparts, nargs);
26126 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
26127 duk_push_number(ctx, d);
26128 }
26129 return 1;
26130}
26131
26132DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
26133 duk_double_t d;
26134
26135 d = DUK_USE_DATE_GET_NOW(ctx);
26136 DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */
26137 duk_push_number(ctx, d);
26138 return 1;
26139}
26140
26141/*
26142 * String/JSON conversions
26143 *
26144 * Human readable conversions are now basically ISO 8601 with a space
26145 * (instead of 'T') as the date/time separator. This is a good baseline
26146 * and is platform independent.
26147 *
26148 * A shared native helper to provide many conversions. Magic value contains
26149 * a set of flags. The helper provides:
26150 *
26151 * toString()
26152 * toDateString()
26153 * toTimeString()
26154 * toLocaleString()
26155 * toLocaleDateString()
26156 * toLocaleTimeString()
26157 * toUTCString()
26158 * toISOString()
26159 *
26160 * Notes:
26161 *
26162 * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
26163 * required to be the same Ecmascript function object (!), so it is
26164 * omitted from here.
26165 *
26166 * - Date.prototype.toUTCString(): E5.1 specification does not require a
26167 * specific format, but result should be human readable. The
26168 * specification suggests using ISO 8601 format with a space (instead
26169 * of 'T') separator if a more human readable format is not available.
26170 *
26171 * - Date.prototype.toISOString(): unlike other conversion functions,
26172 * toISOString() requires a RangeError for invalid date values.
26173 */
26174
26175DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
26176 duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
26177 return duk__to_string_helper(ctx, flags);
26178}
26179
26180DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
26181 /* This native function is also used for Date.prototype.getTime()
26182 * as their behavior is identical.
26183 */
26184
26185 duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ this ] */
26186 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
26187 duk_push_number(ctx, d);
26188 return 1;
26189}
26190
26191DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
26192 /* Note: toJSON() is a generic function which works even if 'this'
26193 * is not a Date. The sole argument is ignored.
26194 */
26195
26196 duk_push_this(ctx);
26197 duk_to_object(ctx, -1);
26198
26199 duk_dup_top(ctx);
26200 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
26201 if (duk_is_number(ctx, -1)) {
26202 duk_double_t d = duk_get_number(ctx, -1);
26203 if (!DUK_ISFINITE(d)) {
26204 duk_push_null(ctx);
26205 return 1;
26206 }
26207 }
26208 duk_pop(ctx);
26209
26210 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
26211 duk_dup(ctx, -2); /* -> [ O toIsoString O ] */
26212 duk_call_method(ctx, 0);
26213 return 1;
26214}
26215
26216/*
26217 * Getters.
26218 *
26219 * Implementing getters is quite easy. The internal time value is either
26220 * NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
26221 * The internal time value can be converted to integer parts, and each
26222 * part will be normalized and will fit into a 32-bit signed integer.
26223 *
26224 * A shared native helper to provide all getters. Magic value contains
26225 * a set of flags and also packs the date component index argument. The
26226 * helper provides:
26227 *
26228 * getFullYear()
26229 * getUTCFullYear()
26230 * getMonth()
26231 * getUTCMonth()
26232 * getDate()
26233 * getUTCDate()
26234 * getDay()
26235 * getUTCDay()
26236 * getHours()
26237 * getUTCHours()
26238 * getMinutes()
26239 * getUTCMinutes()
26240 * getSeconds()
26241 * getUTCSeconds()
26242 * getMilliseconds()
26243 * getUTCMilliseconds()
26244 * getYear()
26245 *
26246 * Notes:
26247 *
26248 * - Date.prototype.getDate(): 'date' means day-of-month, and is
26249 * zero-based in internal calculations but public API expects it to
26250 * be one-based.
26251 *
26252 * - Date.prototype.getTime() and Date.prototype.valueOf() have identical
26253 * behavior. They have separate function objects, but share the same C
26254 * function (duk_bi_date_prototype_value_of).
26255 */
26256
26257DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
26258 duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
26259 return duk__get_part_helper(ctx, flags_and_idx);
26260}
26261
26262DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
26263 /*
26264 * Return (t - LocalTime(t)) in minutes:
26265 *
26266 * t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
26267 * = -(LocalTZA + DaylightSavingTA(t))
26268 *
26269 * where DaylightSavingTA() is checked for time 't'.
26270 *
26271 * Note that the sign of the result is opposite to common usage,
26272 * e.g. for EE(S)T which normally is +2h or +3h from UTC, this
26273 * function returns -120 or -180.
26274 *
26275 */
26276
26277 duk_double_t d;
26278 duk_int_t tzoffset;
26279
26280 /* Note: DST adjustment is determined using UTC time. */
26281 d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
26282 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
26283 if (DUK_ISNAN(d)) {
26284 duk_push_nan(ctx);
26285 } else {
26286 DUK_ASSERT(DUK_ISFINITE(d));
26287 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
26288 duk_push_int(ctx, -tzoffset / 60);
26289 }
26290 return 1;
26291}
26292
26293/*
26294 * Setters.
26295 *
26296 * Setters are a bit more complicated than getters. Component setters
26297 * break down the current time value into its (normalized) component
26298 * parts, replace one or more components with -unnormalized- new values,
26299 * and the components are then converted back into a time value. As an
26300 * example of using unnormalized values:
26301 *
26302 * var d = new Date(1234567890);
26303 *
26304 * is equivalent to:
26305 *
26306 * var d = new Date(0);
26307 * d.setUTCMilliseconds(1234567890);
26308 *
26309 * A shared native helper to provide almost all setters. Magic value
26310 * contains a set of flags and also packs the "maxnargs" argument. The
26311 * helper provides:
26312 *
26313 * setMilliseconds()
26314 * setUTCMilliseconds()
26315 * setSeconds()
26316 * setUTCSeconds()
26317 * setMinutes()
26318 * setUTCMinutes()
26319 * setHours()
26320 * setUTCHours()
26321 * setDate()
26322 * setUTCDate()
26323 * setMonth()
26324 * setUTCMonth()
26325 * setFullYear()
26326 * setUTCFullYear()
26327 * setYear()
26328 *
26329 * Notes:
26330 *
26331 * - Date.prototype.setYear() (Section B addition): special year check
26332 * is omitted. NaN / Infinity will just flow through and ultimately
26333 * result in a NaN internal time value.
26334 *
26335 * - Date.prototype.setYear() does not have optional arguments for
26336 * setting month and day-in-month (like setFullYear()), but we indicate
26337 * 'maxnargs' to be 3 to get the year written to the correct component
26338 * index in duk__set_part_helper(). The function has nargs == 1, so only
26339 * the year will be set regardless of actual argument count.
26340 */
26341
26342DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
26343 duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
26344 return duk__set_part_helper(ctx, flags_and_maxnargs);
26345}
26346
26347DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
26348 duk_double_t d;
26349
26350 (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
26351 d = duk__timeclip(duk_to_number(ctx, 0));
26352 duk_push_number(ctx, d);
26353 duk_dup_top(ctx);
26354 duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
26355
26356 return 1;
26357}
26358#line 1 "duk_bi_date_unix.c"
26359/*
26360 * Unix-like Date providers
26361 *
26362 * Generally useful Unix / POSIX / ANSI Date providers.
26363 */
26364
26365/* include removed: duk_internal.h */
26366
26367/* The necessary #includes are in place in duk_config.h. */
26368
26369/* Buffer sizes for some UNIX calls. Larger than strictly necessary
26370 * to avoid Valgrind errors.
26371 */
26372#define DUK__STRPTIME_BUF_SIZE 64
26373#define DUK__STRFTIME_BUF_SIZE 64
26374
26375#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
26376/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
26377DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
26378 duk_hthread *thr = (duk_hthread *) ctx;
26379 struct timeval tv;
26380 duk_double_t d;
26381
26382 if (gettimeofday(&tv, NULL) != 0) {
26383 DUK_ERROR_INTERNAL_DEFMSG(thr);
26384 }
26385
26386 d = ((duk_double_t) tv.tv_sec) * 1000.0 +
26387 ((duk_double_t) (tv.tv_usec / 1000));
26388 DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions */
26389
26390 return d;
26391}
26392#endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
26393
26394#if defined(DUK_USE_DATE_NOW_TIME)
26395/* Not a very good provider: only full seconds are available. */
26396DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
26397 time_t t;
26398
26399 DUK_UNREF(ctx);
26400 t = time(NULL);
26401 return ((duk_double_t) t) * 1000.0;
26402}
26403#endif /* DUK_USE_DATE_NOW_TIME */
26404
26405#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R)
26406/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
26407DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
26408 time_t t, t1, t2;
26409 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
26410 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
26411 struct tm tms[2];
26412#ifdef DUK_USE_DATE_TZO_GMTIME
26413 struct tm *tm_ptr;
26414#endif
26415
26416 /* For NaN/inf, the return value doesn't matter. */
26417 if (!DUK_ISFINITE(d)) {
26418 return 0;
26419 }
26420
26421 /* If not within Ecmascript range, some integer time calculations
26422 * won't work correctly (and some asserts will fail), so bail out
26423 * if so. This fixes test-bug-date-insane-setyear.js. There is
26424 * a +/- 24h leeway in this range check to avoid a test262 corner
26425 * case documented in test-bug-date-timeval-edges.js.
26426 */
26427 if (!duk_bi_date_timeval_in_leeway_range(d)) {
26428 DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows"));
26429 return 0;
26430 }
26431
26432 /*
26433 * This is a bit tricky to implement portably. The result depends
26434 * on the timestamp (specifically, DST depends on the timestamp).
26435 * If e.g. UNIX APIs are used, they'll have portability issues with
26436 * very small and very large years.
26437 *
26438 * Current approach:
26439 *
26440 * - Stay within portable UNIX limits by using equivalent year mapping.
26441 * Avoid year 1970 and 2038 as some conversions start to fail, at
26442 * least on some platforms. Avoiding 1970 means that there are
26443 * currently DST discrepancies for 1970.
26444 *
26445 * - Create a UTC and local time breakdowns from 't'. Then create
26446 * a time_t using gmtime() and localtime() and compute the time
26447 * difference between the two.
26448 *
26449 * Equivalent year mapping (E5 Section 15.9.1.8):
26450 *
26451 * If the host environment provides functionality for determining
26452 * daylight saving time, the implementation of ECMAScript is free
26453 * to map the year in question to an equivalent year (same
26454 * leap-year-ness and same starting week day for the year) for which
26455 * the host environment provides daylight saving time information.
26456 * The only restriction is that all equivalent years should produce
26457 * the same result.
26458 *
26459 * This approach is quite reasonable but not entirely correct, e.g.
26460 * the specification also states (E5 Section 15.9.1.8):
26461 *
26462 * The implementation of ECMAScript should not try to determine
26463 * whether the exact time was subject to daylight saving time, but
26464 * just whether daylight saving time would have been in effect if
26465 * the _current daylight saving time algorithm_ had been used at the
26466 * time. This avoids complications such as taking into account the
26467 * years that the locale observed daylight saving time year round.
26468 *
26469 * Since we rely on the platform APIs for conversions between local
26470 * time and UTC, we can't guarantee the above. Rather, if the platform
26471 * has historical DST rules they will be applied. This seems to be the
26472 * general preferred direction in Ecmascript standardization (or at least
26473 * implementations) anyway, and even the equivalent year mapping should
26474 * be disabled if the platform is known to handle DST properly for the
26475 * full Ecmascript range.
26476 *
26477 * The following has useful discussion and links:
26478 *
26479 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
26480 */
26481
26482 duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/);
26483 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038);
26484
26485 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
26486 DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */
26487 t = (time_t) (d / 1000.0);
26488 DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
26489
26490 DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2);
26491
26492#if defined(DUK_USE_DATE_TZO_GMTIME_R)
26493 (void) gmtime_r(&t, &tms[0]);
26494 (void) localtime_r(&t, &tms[1]);
26495#elif defined(DUK_USE_DATE_TZO_GMTIME)
26496 tm_ptr = gmtime(&t);
26497 DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
26498 tm_ptr = localtime(&t);
26499 DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm));
26500#else
26501#error internal error
26502#endif
26503 DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
26504 "wday:%ld,yday:%ld,isdst:%ld}",
26505 (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour,
26506 (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year,
26507 (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst));
26508 DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
26509 "wday:%ld,yday:%ld,isdst:%ld}",
26510 (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour,
26511 (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
26512 (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
26513
26514 /* tm_isdst is both an input and an output to mktime(), use 0 to
26515 * avoid DST handling in mktime():
26516 * - https://github.com/svaarala/duktape/issues/406
26517 * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
26518 */
26519 tms[0].tm_isdst = 0;
26520 tms[1].tm_isdst = 0;
26521 t1 = mktime(&tms[0]); /* UTC */
26522 t2 = mktime(&tms[1]); /* local */
26523 if (t1 == (time_t) -1 || t2 == (time_t) -1) {
26524 /* This check used to be for (t < 0) but on some platforms
26525 * time_t is unsigned and apparently the proper way to detect
26526 * an mktime() error return is the cast above. See e.g.:
26527 * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
26528 */
26529 goto error;
26530 }
26531 DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
26532
26533 /* Compute final offset in seconds, positive if local time ahead of
26534 * UTC (returned value is UTC-to-local offset).
26535 *
26536 * difftime() returns a double, so coercion to int generates quite
26537 * a lot of code. Direct subtraction is not portable, however.
26538 * XXX: allow direct subtraction on known platforms.
26539 */
26540#if 0
26541 return (duk_int_t) (t2 - t1);
26542#endif
26543 return (duk_int_t) difftime(t2, t1);
26544
26545 error:
26546 /* XXX: return something more useful, so that caller can throw? */
26547 DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
26548 return 0;
26549}
26550#endif /* DUK_USE_DATE_TZO_GMTIME */
26551
26552#if defined(DUK_USE_DATE_PRS_STRPTIME)
26553DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str) {
26554 struct tm tm;
26555 time_t t;
26556 char buf[DUK__STRPTIME_BUF_SIZE];
26557
26558 /* copy to buffer with spare to avoid Valgrind gripes from strptime */
26559 DUK_ASSERT(str != NULL);
26560 DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
26561 DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
26562 buf[sizeof(buf) - 1] = (char) 0;
26563
26564 DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
26565
26566 DUK_MEMZERO(&tm, sizeof(tm));
26567 if (strptime((const char *) buf, "%c", &tm) != NULL) {
26568 DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
26569 "wday:%ld,yday:%ld,isdst:%ld}",
26570 (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour,
26571 (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year,
26572 (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst));
26573 tm.tm_isdst = -1; /* negative: dst info not available */
26574
26575 t = mktime(&tm);
26576 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
26577 if (t >= 0) {
26578 duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
26579 return 1;
26580 }
26581 }
26582
26583 return 0;
26584}
26585#endif /* DUK_USE_DATE_PRS_STRPTIME */
26586
26587#if defined(DUK_USE_DATE_PRS_GETDATE)
26588DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str) {
26589 struct tm tm;
26590 duk_small_int_t rc;
26591 time_t t;
26592
26593 /* For this to work, DATEMSK must be set, so this is not very
26594 * convenient for an embeddable interpreter.
26595 */
26596
26597 DUK_MEMZERO(&tm, sizeof(struct tm));
26598 rc = (duk_small_int_t) getdate_r(str, &tm);
26599 DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
26600
26601 if (rc == 0) {
26602 t = mktime(&tm);
26603 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
26604 if (t >= 0) {
26605 duk_push_number(ctx, (duk_double_t) t);
26606 return 1;
26607 }
26608 }
26609
26610 return 0;
26611}
26612#endif /* DUK_USE_DATE_PRS_GETDATE */
26613
26614#if defined(DUK_USE_DATE_FMT_STRFTIME)
26615DUK_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) {
26616 char buf[DUK__STRFTIME_BUF_SIZE];
26617 struct tm tm;
26618 const char *fmt;
26619
26620 DUK_UNREF(tzoffset);
26621
26622 /* If the platform doesn't support the entire Ecmascript range, we need
26623 * to return 0 so that the caller can fall back to the default formatter.
26624 *
26625 * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript
26626 * range is supported. For smaller time_t values (4 bytes in practice),
26627 * assumes that the signed 32-bit range is supported.
26628 *
26629 * XXX: detect this more correctly per platform. The size of time_t is
26630 * probably not an accurate guarantee of strftime() supporting or not
26631 * supporting a large time range (the full Ecmascript range).
26632 */
26633 if (sizeof(time_t) < 8 &&
26634 (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
26635 /* be paranoid for 32-bit time values (even avoiding negative ones) */
26636 return 0;
26637 }
26638
26639 DUK_MEMZERO(&tm, sizeof(tm));
26640 tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
26641 tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
26642 tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
26643 tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */
26644 tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */
26645 tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
26646 tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
26647 tm.tm_isdst = 0;
26648
26649 DUK_MEMZERO(buf, sizeof(buf));
26650 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
26651 fmt = "%c";
26652 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
26653 fmt = "%x";
26654 } else {
26655 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
26656 fmt = "%X";
26657 }
26658 (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
26659 DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
26660
26661 duk_push_string(ctx, buf);
26662 return 1;
26663}
26664#endif /* DUK_USE_DATE_FMT_STRFTIME */
26665
26666#undef DUK__STRPTIME_BUF_SIZE
26667#undef DUK__STRFTIME_BUF_SIZE
26668#line 1 "duk_bi_date_windows.c"
26669/*
26670 * Windows Date providers
26671 *
26672 * Platform specific links:
26673 *
26674 * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
26675 */
26676
26677/* include removed: duk_internal.h */
26678
26679/* The necessary #includes are in place in duk_config.h. */
26680
26681#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
26682/* Shared Windows helpers. */
26683DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
26684 FILETIME ft;
26685 if (SystemTimeToFileTime(st, &ft) == 0) {
26686 DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
26687 res->QuadPart = 0;
26688 } else {
26689 res->LowPart = ft.dwLowDateTime;
26690 res->HighPart = ft.dwHighDateTime;
26691 }
26692}
26693DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
26694 DUK_MEMZERO((void *) st, sizeof(*st));
26695 st->wYear = 1970;
26696 st->wMonth = 1;
26697 st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
26698 st->wDay = 1;
26699 DUK_ASSERT(st->wHour == 0);
26700 DUK_ASSERT(st->wMinute == 0);
26701 DUK_ASSERT(st->wSecond == 0);
26702 DUK_ASSERT(st->wMilliseconds == 0);
26703}
26704#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
26705
26706#ifdef DUK_USE_DATE_NOW_WINDOWS
26707DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
26708 /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
26709 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
26710 */
26711 SYSTEMTIME st1, st2;
26712 ULARGE_INTEGER tmp1, tmp2;
26713
26714 DUK_UNREF(ctx);
26715
26716 GetSystemTime(&st1);
26717 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
26718
26719 duk__set_systime_jan1970(&st2);
26720 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
26721
26722 /* Difference is in 100ns units, convert to milliseconds w/o fractions */
26723 return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
26724}
26725#endif /* DUK_USE_DATE_NOW_WINDOWS */
26726
26727
26728#if defined(DUK_USE_DATE_TZO_WINDOWS)
26729DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
26730 SYSTEMTIME st1;
26731 SYSTEMTIME st2;
26732 SYSTEMTIME st3;
26733 ULARGE_INTEGER tmp1;
26734 ULARGE_INTEGER tmp2;
26735 ULARGE_INTEGER tmp3;
26736 FILETIME ft1;
26737
26738 /* XXX: handling of timestamps outside Windows supported range.
26739 * How does Windows deal with dates before 1600? Does windows
26740 * support all Ecmascript years (like -200000 and +200000)?
26741 * Should equivalent year mapping be used here too? If so, use
26742 * a shared helper (currently integrated into timeval-to-parts).
26743 */
26744
26745 /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
26746 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
26747 */
26748
26749 duk__set_systime_jan1970(&st1);
26750 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
26751 tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
26752 tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */
26753
26754 ft1.dwLowDateTime = tmp2.LowPart;
26755 ft1.dwHighDateTime = tmp2.HighPart;
26756 FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
26757 if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
26758 DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
26759 return 0;
26760 }
26761 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
26762
26763 /* Positive if local time ahead of UTC. */
26764 return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */
26765}
26766#endif /* DUK_USE_DATE_TZO_WINDOWS */
26767#line 1 "duk_bi_duktape.c"
26768/*
26769 * Duktape built-ins
26770 *
26771 * Size optimization note: it might seem that vararg multipurpose functions
26772 * like fin(), enc(), and dec() are not very size optimal, but using a single
26773 * user-visible Ecmascript function saves a lot of run-time footprint; each
26774 * Function instance takes >100 bytes. Using a shared native helper and a
26775 * 'magic' value won't save much if there are multiple Function instances
26776 * anyway.
26777 */
26778
26779/* include removed: duk_internal.h */
26780
26781/* Raw helper to extract internal information / statistics about a value.
26782 * The return values are version specific and must not expose anything
26783 * that would lead to security issues (e.g. exposing compiled function
26784 * 'data' buffer might be an issue). Currently only counts and sizes and
26785 * such are given so there should not be a security impact.
26786 */
26787DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
26788 duk_hthread *thr = (duk_hthread *) ctx;
26789 duk_tval *tv;
26790 duk_heaphdr *h;
26791 duk_int_t i, n;
26792
26793 DUK_UNREF(thr);
26794
26795 /* result array */
26796 duk_push_array(ctx); /* -> [ val arr ] */
26797
26798 /* type tag (public) */
26799 duk_push_int(ctx, duk_get_type(ctx, 0));
26800
26801 /* address */
26802 tv = duk_get_tval(ctx, 0);
26803 DUK_ASSERT(tv != NULL); /* because arg count is 1 */
26804 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
26805 h = DUK_TVAL_GET_HEAPHDR(tv);
26806 duk_push_pointer(ctx, (void *) h);
26807 } else {
26808 /* internal type tag */
26809 duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv));
26810 goto done;
26811 }
26812 DUK_ASSERT(h != NULL);
26813
26814 /* refcount */
26815#ifdef DUK_USE_REFERENCE_COUNTING
26816 duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
26817#else
26818 duk_push_undefined(ctx);
26819#endif
26820
26821 /* heaphdr size and additional allocation size, followed by
26822 * type specific stuff (with varying value count)
26823 */
26824 switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
26825 case DUK_HTYPE_STRING: {
26826 duk_hstring *h_str = (duk_hstring *) h;
26827 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
26828 break;
26829 }
26830 case DUK_HTYPE_OBJECT: {
26831 duk_hobject *h_obj = (duk_hobject *) h;
26832 duk_small_uint_t hdr_size;
26833 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
26834 hdr_size = (duk_small_uint_t) sizeof(duk_hcompiledfunction);
26835 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
26836 hdr_size = (duk_small_uint_t) sizeof(duk_hnativefunction);
26837 } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
26838 hdr_size = (duk_small_uint_t) sizeof(duk_hthread);
26839#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
26840 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
26841 hdr_size = (duk_small_uint_t) sizeof(duk_hbufferobject);
26842#endif
26843 } else {
26844 hdr_size = (duk_small_uint_t) sizeof(duk_hobject);
26845 }
26846 duk_push_uint(ctx, (duk_uint_t) hdr_size);
26847 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj));
26848 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
26849 /* Note: e_next indicates the number of gc-reachable entries
26850 * in the entry part, and also indicates the index where the
26851 * next new property would be inserted. It does *not* indicate
26852 * the number of non-NULL keys present in the object. That
26853 * value could be counted separately but requires a pass through
26854 * the key list.
26855 */
26856 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
26857 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
26858 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
26859 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
26860 duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj);
26861 if (h_data) {
26862 duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_data));
26863 } else {
26864 duk_push_uint(ctx, 0);
26865 }
26866 }
26867 break;
26868 }
26869 case DUK_HTYPE_BUFFER: {
26870 duk_hbuffer *h_buf = (duk_hbuffer *) h;
26871 if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
26872 if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
26873 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_external)));
26874 } else {
26875 /* When alloc_size == 0 the second allocation may not
26876 * actually exist.
26877 */
26878 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_dynamic)));
26879 }
26880 duk_push_uint(ctx, (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf)));
26881 } else {
26882 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
26883 }
26884 break;
26885
26886 }
26887 }
26888
26889 done:
26890 /* set values into ret array */
26891 /* XXX: primitive to make array from valstack slice */
26892 n = duk_get_top(ctx);
26893 for (i = 2; i < n; i++) {
26894 duk_dup(ctx, i);
26895 duk_put_prop_index(ctx, 1, i - 2);
26896 }
26897 duk_dup(ctx, 1);
26898 return 1;
26899}
26900
26901DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
26902 duk_hthread *thr = (duk_hthread *) ctx;
26903 duk_activation *act;
26904 duk_uint_fast32_t pc;
26905 duk_uint_fast32_t line;
26906 duk_int_t level;
26907
26908 /* -1 = top callstack entry, callstack[callstack_top - 1]
26909 * -callstack_top = bottom callstack entry, callstack[0]
26910 */
26911 level = duk_to_int(ctx, 0);
26912 if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
26913 return 0;
26914 }
26915 DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
26916 act = thr->callstack + thr->callstack_top + level;
26917
26918 duk_push_object(ctx);
26919
26920 duk_push_tval(ctx, &act->tv_func);
26921
26922 /* Relevant PC is just before current one because PC is
26923 * post-incremented. This should match what error augment
26924 * code does.
26925 */
26926 pc = duk_hthread_get_act_prev_pc(thr, act);
26927 duk_push_uint(ctx, (duk_uint_t) pc);
26928
26929#if defined(DUK_USE_PC2LINE)
26930 line = duk_hobject_pc2line_query(ctx, -2, pc);
26931#else
26932 line = 0;
26933#endif
26934 duk_push_uint(ctx, (duk_uint_t) line);
26935
26936 /* Providing access to e.g. act->lex_env would be dangerous: these
26937 * internal structures must never be accessible to the application.
26938 * Duktape relies on them having consistent data, and this consistency
26939 * is only asserted for, not checked for.
26940 */
26941
26942 /* [ level obj func pc line ] */
26943
26944 /* XXX: version specific array format instead? */
26945 duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER);
26946 duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC);
26947 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION);
26948 return 1;
26949}
26950
26951DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
26952#ifdef DUK_USE_MARK_AND_SWEEP
26953 duk_hthread *thr = (duk_hthread *) ctx;
26954 duk_small_uint_t flags;
26955 duk_bool_t rc;
26956
26957 flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
26958 rc = duk_heap_mark_and_sweep(thr->heap, flags);
26959
26960 /* XXX: Not sure what the best return value would be in the API.
26961 * Return a boolean for now. Note that rc == 0 is success (true).
26962 */
26963 duk_push_boolean(ctx, !rc);
26964 return 1;
26965#else
26966 DUK_UNREF(ctx);
26967 return 0;
26968#endif
26969}
26970
26971DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
26972 (void) duk_require_hobject(ctx, 0);
26973 if (duk_get_top(ctx) >= 2) {
26974 /* Set: currently a finalizer is disabled by setting it to
26975 * undefined; this does not remove the property at the moment.
26976 * The value could be type checked to be either a function
26977 * or something else; if something else, the property could
26978 * be deleted.
26979 */
26980 duk_set_top(ctx, 2);
26981 (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
26982 return 0;
26983 } else {
26984 /* Get. */
26985 DUK_ASSERT(duk_get_top(ctx) == 1);
26986 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
26987 return 1;
26988 }
26989}
26990
26991DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
26992 duk_hthread *thr = (duk_hthread *) ctx;
26993 duk_hstring *h_str;
26994
26995 DUK_UNREF(thr);
26996
26997 /* Vararg function: must be careful to check/require arguments.
26998 * The JSON helpers accept invalid indices and treat them like
26999 * non-existent optional parameters.
27000 */
27001
27002 h_str = duk_require_hstring(ctx, 0);
27003 duk_require_valid_index(ctx, 1);
27004
27005 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
27006 duk_set_top(ctx, 2);
27007 duk_hex_encode(ctx, 1);
27008 DUK_ASSERT_TOP(ctx, 2);
27009 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
27010 duk_set_top(ctx, 2);
27011 duk_base64_encode(ctx, 1);
27012 DUK_ASSERT_TOP(ctx, 2);
27013#ifdef DUK_USE_JX
27014 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
27015 duk_bi_json_stringify_helper(ctx,
27016 1 /*idx_value*/,
27017 2 /*idx_replacer*/,
27018 3 /*idx_space*/,
27019 DUK_JSON_FLAG_EXT_CUSTOM |
27020 DUK_JSON_FLAG_ASCII_ONLY |
27021 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
27022#endif
27023#ifdef DUK_USE_JC
27024 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
27025 duk_bi_json_stringify_helper(ctx,
27026 1 /*idx_value*/,
27027 2 /*idx_replacer*/,
27028 3 /*idx_space*/,
27029 DUK_JSON_FLAG_EXT_COMPATIBLE |
27030 DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
27031#endif
27032 } else {
27033 return DUK_RET_TYPE_ERROR;
27034 }
27035 return 1;
27036}
27037
27038DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
27039 duk_hthread *thr = (duk_hthread *) ctx;
27040 duk_hstring *h_str;
27041
27042 DUK_UNREF(thr);
27043
27044 /* Vararg function: must be careful to check/require arguments.
27045 * The JSON helpers accept invalid indices and treat them like
27046 * non-existent optional parameters.
27047 */
27048
27049 h_str = duk_require_hstring(ctx, 0);
27050 duk_require_valid_index(ctx, 1);
27051
27052 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
27053 duk_set_top(ctx, 2);
27054 duk_hex_decode(ctx, 1);
27055 DUK_ASSERT_TOP(ctx, 2);
27056 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
27057 duk_set_top(ctx, 2);
27058 duk_base64_decode(ctx, 1);
27059 DUK_ASSERT_TOP(ctx, 2);
27060#ifdef DUK_USE_JX
27061 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
27062 duk_bi_json_parse_helper(ctx,
27063 1 /*idx_value*/,
27064 2 /*idx_replacer*/,
27065 DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
27066#endif
27067#ifdef DUK_USE_JC
27068 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
27069 duk_bi_json_parse_helper(ctx,
27070 1 /*idx_value*/,
27071 2 /*idx_replacer*/,
27072 DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
27073#endif
27074 } else {
27075 return DUK_RET_TYPE_ERROR;
27076 }
27077 return 1;
27078}
27079
27080/*
27081 * Compact an object
27082 */
27083
27084DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
27085 DUK_ASSERT_TOP(ctx, 1);
27086 duk_compact(ctx, 0);
27087 return 1; /* return the argument object */
27088}
27089#line 1 "duk_bi_error.c"
27090/*
27091 * Error built-ins
27092 */
27093
27094/* include removed: duk_internal.h */
27095
27096DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
27097 /* Behavior for constructor and non-constructor call is
27098 * the same except for augmenting the created error. When
27099 * called as a constructor, the caller (duk_new()) will handle
27100 * augmentation; when called as normal function, we need to do
27101 * it here.
27102 */
27103
27104 duk_hthread *thr = (duk_hthread *) ctx;
27105 duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
27106
27107 /* same for both error and each subclass like TypeError */
27108 duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
27109 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
27110
27111 DUK_UNREF(thr);
27112
27113 duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
27114
27115 /* If message is undefined, the own property 'message' is not set at
27116 * all to save property space. An empty message is inherited anyway.
27117 */
27118 if (!duk_is_undefined(ctx, 0)) {
27119 duk_to_string(ctx, 0);
27120 duk_dup(ctx, 0); /* [ message error message ] */
27121 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
27122 }
27123
27124 /* Augment the error if called as a normal function. __FILE__ and __LINE__
27125 * are not desirable in this case.
27126 */
27127
27128#ifdef DUK_USE_AUGMENT_ERROR_CREATE
27129 if (!duk_is_constructor_call(ctx)) {
27130 duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
27131 }
27132#endif
27133
27134 return 1;
27135}
27136
27137DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
27138 /* XXX: optimize with more direct internal access */
27139
27140 duk_push_this(ctx);
27141 (void) duk_require_hobject_or_lfunc_coerce(ctx, -1);
27142
27143 /* [ ... this ] */
27144
27145 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
27146 if (duk_is_undefined(ctx, -1)) {
27147 duk_pop(ctx);
27148 duk_push_string(ctx, "Error");
27149 } else {
27150 duk_to_string(ctx, -1);
27151 }
27152
27153 /* [ ... this name ] */
27154
27155 /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
27156 * accident or are they actually needed? The first ToString()
27157 * could conceivably return 'undefined'.
27158 */
27159 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
27160 if (duk_is_undefined(ctx, -1)) {
27161 duk_pop(ctx);
27162 duk_push_string(ctx, "");
27163 } else {
27164 duk_to_string(ctx, -1);
27165 }
27166
27167 /* [ ... this name message ] */
27168
27169 if (duk_get_length(ctx, -2) == 0) {
27170 /* name is empty -> return message */
27171 return 1;
27172 }
27173 if (duk_get_length(ctx, -1) == 0) {
27174 /* message is empty -> return name */
27175 duk_pop(ctx);
27176 return 1;
27177 }
27178 duk_push_string(ctx, ": ");
27179 duk_insert(ctx, -2); /* ... name ': ' message */
27180 duk_concat(ctx, 3);
27181
27182 return 1;
27183}
27184
27185#if defined(DUK_USE_TRACEBACKS)
27186
27187/*
27188 * Traceback handling
27189 *
27190 * The unified helper decodes the traceback and produces various requested
27191 * outputs. It should be optimized for size, and may leave garbage on stack,
27192 * only the topmost return value matters. For instance, traceback separator
27193 * and decoded strings are pushed even when looking for filename only.
27194 *
27195 * NOTE: although _Tracedata is an internal property, user code can currently
27196 * write to the array (or replace it with something other than an array).
27197 * The code below must tolerate arbitrary _Tracedata. It can throw errors
27198 * etc, but cannot cause a segfault or memory unsafe behavior.
27199 */
27200
27201/* constants arbitrary, chosen for small loads */
27202#define DUK__OUTPUT_TYPE_TRACEBACK (-1)
27203#define DUK__OUTPUT_TYPE_FILENAME 0
27204#define DUK__OUTPUT_TYPE_LINENUMBER 1
27205
27206DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
27207 duk_hthread *thr = (duk_hthread *) ctx;
27208 duk_idx_t idx_td;
27209 duk_small_int_t i; /* traceback depth fits into 16 bits */
27210 duk_small_int_t t; /* stack type fits into 16 bits */
27211 duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */
27212 const char *str_tailcall = " tailcall";
27213 const char *str_strict = " strict";
27214 const char *str_construct = " construct";
27215 const char *str_prevyield = " preventsyield";
27216 const char *str_directeval = " directeval";
27217 const char *str_empty = "";
27218
27219 DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
27220 DUK_UNREF(thr);
27221
27222 duk_push_this(ctx);
27223 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
27224 idx_td = duk_get_top_index(ctx);
27225
27226 duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
27227 duk_push_this(ctx);
27228
27229 /* [ ... this tracedata sep this ] */
27230
27231 /* XXX: skip null filename? */
27232
27233 if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
27234 /* Current tracedata contains 2 entries per callstack entry. */
27235 for (i = 0; ; i += 2) {
27236 duk_int_t pc;
27237 duk_int_t line;
27238 duk_int_t flags;
27239 duk_double_t d;
27240 const char *funcname;
27241 const char *filename;
27242 duk_hobject *h_func;
27243 duk_hstring *h_name;
27244
27245 duk_require_stack(ctx, 5);
27246 duk_get_prop_index(ctx, idx_td, i);
27247 duk_get_prop_index(ctx, idx_td, i + 1);
27248 d = duk_to_number(ctx, -1);
27249 pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
27250 flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
27251 t = (duk_small_int_t) duk_get_type(ctx, -2);
27252
27253 if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
27254 /*
27255 * Ecmascript/native function call or lightfunc call
27256 */
27257
27258 count_func++;
27259
27260 /* [ ... v1(func) v2(pc+flags) ] */
27261
27262 h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
27263
27264 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
27265 duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);
27266
27267#if defined(DUK_USE_PC2LINE)
27268 line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
27269#else
27270 line = 0;
27271#endif
27272
27273 /* [ ... v1 v2 name filename ] */
27274
27275 /* When looking for .fileName/.lineNumber, blame first
27276 * function which has a .fileName.
27277 */
27278 if (duk_is_string(ctx, -1)) {
27279 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
27280 return 1;
27281 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
27282 duk_push_int(ctx, line);
27283 return 1;
27284 }
27285 }
27286
27287 /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
27288 /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
27289 h_name = duk_get_hstring(ctx, -2); /* may be NULL */
27290 funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
27291 "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
27292 filename = duk_get_string(ctx, -1);
27293 filename = filename ? filename : "";
27294 DUK_ASSERT(funcname != NULL);
27295 DUK_ASSERT(filename != NULL);
27296
27297 if (h_func == NULL) {
27298 duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
27299 (const char *) funcname,
27300 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
27301 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
27302 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
27303 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
27304 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
27305 } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
27306 duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
27307 (const char *) funcname,
27308 (const char *) filename,
27309 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
27310 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
27311 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
27312 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
27313 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
27314 } else {
27315 duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
27316 (const char *) funcname,
27317 (const char *) filename,
27318 (long) line,
27319 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
27320 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
27321 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
27322 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
27323 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
27324 }
27325 duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
27326 duk_pop_n(ctx, 3); /* -> [ ... str ] */
27327 } else if (t == DUK_TYPE_STRING) {
27328 /*
27329 * __FILE__ / __LINE__ entry, here 'pc' is line number directly.
27330 * Sometimes __FILE__ / __LINE__ is reported as the source for
27331 * the error (fileName, lineNumber), sometimes not.
27332 */
27333
27334 /* [ ... v1(filename) v2(line+flags) ] */
27335
27336 /* When looking for .fileName/.lineNumber, blame compilation
27337 * or C call site unless flagged not to do so.
27338 */
27339 if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
27340 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
27341 duk_pop(ctx);
27342 return 1;
27343 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
27344 duk_push_int(ctx, pc);
27345 return 1;
27346 }
27347 }
27348
27349 duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
27350 (const char *) duk_get_string(ctx, -2), (long) pc);
27351 duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
27352 duk_pop(ctx); /* -> [ ... str ] */
27353 } else {
27354 /* unknown, ignore */
27355 duk_pop_2(ctx);
27356 break;
27357 }
27358 }
27359
27360 if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
27361 /* Possibly truncated; there is no explicit truncation
27362 * marker so this is the best we can do.
27363 */
27364
27365 duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
27366 }
27367 }
27368
27369 /* [ ... this tracedata sep this str1 ... strN ] */
27370
27371 if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
27372 return 0;
27373 } else {
27374 /* The 'this' after 'sep' will get ToString() coerced by
27375 * duk_join() automatically. We don't want to do that
27376 * coercion when providing .fileName or .lineNumber (GH-254).
27377 */
27378 duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
27379 return 1;
27380 }
27381}
27382
27383/* XXX: Output type could be encoded into native function 'magic' value to
27384 * save space. For setters the stridx could be encoded into 'magic'.
27385 */
27386
27387DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
27388 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
27389}
27390
27391DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
27392 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
27393}
27394
27395DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
27396 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
27397}
27398
27399#undef DUK__OUTPUT_TYPE_TRACEBACK
27400#undef DUK__OUTPUT_TYPE_FILENAME
27401#undef DUK__OUTPUT_TYPE_LINENUMBER
27402
27403#else /* DUK_USE_TRACEBACKS */
27404
27405/*
27406 * Traceback handling when tracebacks disabled.
27407 *
27408 * The fileName / lineNumber stubs are now necessary because built-in
27409 * data will include the accessor properties in Error.prototype. If those
27410 * are removed for builds without tracebacks, these can also be removed.
27411 * 'stack' should still be present and produce a ToString() equivalent:
27412 * this is useful for user code which prints a stacktrace and expects to
27413 * see something useful. A normal stacktrace also begins with a ToString()
27414 * of the error so this makes sense.
27415 */
27416
27417DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
27418 /* XXX: remove this native function and map 'stack' accessor
27419 * to the toString() implementation directly.
27420 */
27421 return duk_bi_error_prototype_to_string(ctx);
27422}
27423
27424DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
27425 DUK_UNREF(ctx);
27426 return 0;
27427}
27428
27429DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
27430 DUK_UNREF(ctx);
27431 return 0;
27432}
27433
27434#endif /* DUK_USE_TRACEBACKS */
27435
27436DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
27437 /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
27438 * user code called Object.defineProperty() to create an overriding
27439 * own property. This allows user code to overwrite .fileName etc
27440 * intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
27441 * See https://github.com/svaarala/duktape/issues/387.
27442 */
27443
27444 DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
27445
27446 duk_push_this(ctx);
27447 duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
27448 duk_dup(ctx, 0);
27449
27450 /* [ ... obj key value ] */
27451
27452 DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
27453 duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
27454
27455 duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
27456 DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
27457 DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
27458 DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
27459 return 0;
27460}
27461
27462DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
27463 return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
27464}
27465
27466DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
27467 return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
27468}
27469
27470DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
27471 return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
27472}
27473#line 1 "duk_bi_function.c"
27474/*
27475 * Function built-ins
27476 */
27477
27478/* include removed: duk_internal.h */
27479
27480DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
27481 duk_hthread *thr = (duk_hthread *) ctx;
27482 duk_hstring *h_sourcecode;
27483 duk_idx_t nargs;
27484 duk_idx_t i;
27485 duk_small_uint_t comp_flags;
27486 duk_hcompiledfunction *func;
27487 duk_hobject *outer_lex_env;
27488 duk_hobject *outer_var_env;
27489
27490 /* normal and constructor calls have identical semantics */
27491
27492 nargs = duk_get_top(ctx);
27493 for (i = 0; i < nargs; i++) {
27494 duk_to_string(ctx, i);
27495 }
27496
27497 if (nargs == 0) {
27498 duk_push_string(ctx, "");
27499 duk_push_string(ctx, "");
27500 } else if (nargs == 1) {
27501 /* XXX: cover this with the generic >1 case? */
27502 duk_push_string(ctx, "");
27503 } else {
27504 duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
27505 duk_push_string(ctx, ",");
27506 duk_insert(ctx, 1);
27507 duk_join(ctx, nargs - 1);
27508 }
27509
27510 /* [ body formals ], formals is comma separated list that needs to be parsed */
27511
27512 DUK_ASSERT_TOP(ctx, 2);
27513
27514 /* XXX: this placeholder is not always correct, but use for now.
27515 * It will fail in corner cases; see test-dev-func-cons-args.js.
27516 */
27517 duk_push_string(ctx, "function(");
27518 duk_dup(ctx, 1);
27519 duk_push_string(ctx, "){");
27520 duk_dup(ctx, 0);
27521 duk_push_string(ctx, "}");
27522 duk_concat(ctx, 5);
27523
27524 /* [ body formals source ] */
27525
27526 DUK_ASSERT_TOP(ctx, 3);
27527
27528 /* strictness is not inherited, intentional */
27529 comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
27530
27531 duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
27532 h_sourcecode = duk_require_hstring(ctx, -2);
27533 duk_js_compile(thr,
27534 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
27535 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
27536 comp_flags);
27537 func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
27538 DUK_ASSERT(func != NULL);
27539 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
27540
27541 /* [ body formals source template ] */
27542
27543 /* only outer_lex_env matters, as functions always get a new
27544 * variable declaration environment.
27545 */
27546
27547 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
27548 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
27549
27550 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
27551
27552 /* [ body formals source template closure ] */
27553
27554 return 1;
27555}
27556
27557DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
27558 /* ignore arguments, return undefined (E5 Section 15.3.4) */
27559 DUK_UNREF(ctx);
27560 return 0;
27561}
27562
27563DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
27564 duk_tval *tv;
27565
27566 /*
27567 * E5 Section 15.3.4.2 places few requirements on the output of
27568 * this function:
27569 *
27570 * - The result is an implementation dependent representation
27571 * of the function; in particular
27572 *
27573 * - The result must follow the syntax of a FunctionDeclaration.
27574 * In particular, the function must have a name (even in the
27575 * case of an anonymous function or a function with an empty
27576 * name).
27577 *
27578 * - Note in particular that the output does NOT need to compile
27579 * into anything useful.
27580 */
27581
27582
27583 /* XXX: faster internal way to get this */
27584 duk_push_this(ctx);
27585 tv = duk_get_tval(ctx, -1);
27586 DUK_ASSERT(tv != NULL);
27587
27588 if (DUK_TVAL_IS_OBJECT(tv)) {
27589 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
27590 const char *func_name;
27591
27592 /* Function name: missing/undefined is mapped to empty string,
27593 * otherwise coerce to string.
27594 */
27595 /* XXX: currently no handling for non-allowed identifier characters,
27596 * e.g. a '{' in the function name.
27597 */
27598 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
27599 if (duk_is_undefined(ctx, -1)) {
27600 func_name = "";
27601 } else {
27602 func_name = duk_to_string(ctx, -1);
27603 DUK_ASSERT(func_name != NULL);
27604 }
27605
27606 /* Indicate function type in the function body using a dummy
27607 * directive.
27608 */
27609 if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
27610 duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name);
27611 } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
27612 duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name);
27613 } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
27614 duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name);
27615 } else {
27616 goto type_error;
27617 }
27618 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
27619 duk_push_lightfunc_tostring(ctx, tv);
27620 } else {
27621 goto type_error;
27622 }
27623
27624 return 1;
27625
27626 type_error:
27627 return DUK_RET_TYPE_ERROR;
27628}
27629
27630DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
27631 duk_idx_t len;
27632 duk_idx_t i;
27633
27634 DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
27635
27636 duk_push_this(ctx);
27637 if (!duk_is_callable(ctx, -1)) {
27638 DUK_DDD(DUK_DDDPRINT("func is not callable"));
27639 goto type_error;
27640 }
27641 duk_insert(ctx, 0);
27642 DUK_ASSERT_TOP(ctx, 3);
27643
27644 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
27645 (duk_tval *) duk_get_tval(ctx, 0),
27646 (duk_tval *) duk_get_tval(ctx, 1),
27647 (duk_tval *) duk_get_tval(ctx, 2)));
27648
27649 /* [ func thisArg argArray ] */
27650
27651 if (duk_is_null_or_undefined(ctx, 2)) {
27652 DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
27653 len = 0;
27654 } else if (!duk_is_object(ctx, 2)) {
27655 goto type_error;
27656 } else {
27657 DUK_DDD(DUK_DDDPRINT("argArray is an object"));
27658
27659 /* XXX: make this an internal helper */
27660 duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
27661 len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
27662 duk_pop(ctx);
27663
27664 duk_require_stack(ctx, len);
27665
27666 DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
27667 for (i = 0; i < len; i++) {
27668 duk_get_prop_index(ctx, 2, i);
27669 }
27670 }
27671 duk_remove(ctx, 2);
27672 DUK_ASSERT_TOP(ctx, 2 + len);
27673
27674 /* [ func thisArg arg1 ... argN ] */
27675
27676 DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
27677 (duk_tval *) duk_get_tval(ctx, 0),
27678 (duk_tval *) duk_get_tval(ctx, 1),
27679 (long) len));
27680 duk_call_method(ctx, len);
27681 return 1;
27682
27683 type_error:
27684 return DUK_RET_TYPE_ERROR;
27685}
27686
27687DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
27688 duk_idx_t nargs;
27689
27690 /* Step 1 is not necessary because duk_call_method() will take
27691 * care of it.
27692 */
27693
27694 /* vararg function, thisArg needs special handling */
27695 nargs = duk_get_top(ctx); /* = 1 + arg count */
27696 if (nargs == 0) {
27697 duk_push_undefined(ctx);
27698 nargs++;
27699 }
27700 DUK_ASSERT(nargs >= 1);
27701
27702 /* [ thisArg arg1 ... argN ] */
27703
27704 duk_push_this(ctx); /* 'func' in the algorithm */
27705 duk_insert(ctx, 0);
27706
27707 /* [ func thisArg arg1 ... argN ] */
27708
27709 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
27710 (duk_tval *) duk_get_tval(ctx, 0),
27711 (duk_tval *) duk_get_tval(ctx, 1),
27712 (long) (nargs - 1),
27713 (long) duk_get_top(ctx)));
27714 duk_call_method(ctx, nargs - 1);
27715 return 1;
27716}
27717
27718/* XXX: the implementation now assumes "chained" bound functions,
27719 * whereas "collapsed" bound functions (where there is ever only
27720 * one bound function which directly points to a non-bound, final
27721 * function) would require a "collapsing" implementation which
27722 * merges argument lists etc here.
27723 */
27724DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
27725 duk_hobject *h_bound;
27726 duk_hobject *h_target;
27727 duk_idx_t nargs;
27728 duk_idx_t i;
27729
27730 /* vararg function, careful arg handling (e.g. thisArg may not be present) */
27731 nargs = duk_get_top(ctx); /* = 1 + arg count */
27732 if (nargs == 0) {
27733 duk_push_undefined(ctx);
27734 nargs++;
27735 }
27736 DUK_ASSERT(nargs >= 1);
27737
27738 duk_push_this(ctx);
27739 if (!duk_is_callable(ctx, -1)) {
27740 DUK_DDD(DUK_DDDPRINT("func is not callable"));
27741 goto type_error;
27742 }
27743
27744 /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
27745 DUK_ASSERT_TOP(ctx, nargs + 1);
27746
27747 /* create bound function object */
27748 duk_push_object_helper(ctx,
27749 DUK_HOBJECT_FLAG_EXTENSIBLE |
27750 DUK_HOBJECT_FLAG_BOUND |
27751 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
27752 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
27753 DUK_BIDX_FUNCTION_PROTOTYPE);
27754 h_bound = duk_get_hobject(ctx, -1);
27755 DUK_ASSERT(h_bound != NULL);
27756
27757 /* [ thisArg arg1 ... argN func boundFunc ] */
27758 duk_dup(ctx, -2); /* func */
27759 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
27760
27761 duk_dup(ctx, 0); /* thisArg */
27762 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
27763
27764 duk_push_array(ctx);
27765
27766 /* [ thisArg arg1 ... argN func boundFunc argArray ] */
27767
27768 for (i = 0; i < nargs - 1; i++) {
27769 duk_dup(ctx, 1 + i);
27770 duk_put_prop_index(ctx, -2, i);
27771 }
27772 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
27773
27774 /* [ thisArg arg1 ... argN func boundFunc ] */
27775
27776 /* bound function 'length' property is interesting */
27777 h_target = duk_get_hobject(ctx, -2);
27778 if (h_target == NULL || /* lightfunc */
27779 DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
27780 /* For lightfuncs, simply read the virtual property. */
27781 duk_int_t tmp;
27782 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
27783 tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
27784 duk_pop(ctx);
27785 duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
27786 } else {
27787 duk_push_int(ctx, 0);
27788 }
27789 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */
27790
27791 /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
27792 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
27793 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
27794
27795 /* these non-standard properties are copied for convenience */
27796 /* XXX: 'copy properties' API call? */
27797 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
27798 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
27799 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
27800 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
27801
27802 /* The 'strict' flag is copied to get the special [[Get]] of E5.1
27803 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
27804 * function. Not sure if this is correct, because the specification
27805 * is a bit ambiguous on this point but it would make sense.
27806 */
27807 if (h_target == NULL) {
27808 /* Lightfuncs are always strict. */
27809 DUK_HOBJECT_SET_STRICT(h_bound);
27810 } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
27811 DUK_HOBJECT_SET_STRICT(h_bound);
27812 }
27813 DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
27814
27815 return 1;
27816
27817 type_error:
27818 return DUK_RET_TYPE_ERROR;
27819}
27820#line 1 "duk_bi_global.c"
27821/*
27822 * Global object built-ins
27823 */
27824
27825/* include removed: duk_internal.h */
27826
27827/*
27828 * Encoding/decoding helpers
27829 */
27830
27831/* XXX: Could add fast path (for each transform callback) with direct byte
27832 * lookups (no shifting) and no explicit check for x < 0x80 before table
27833 * lookup.
27834 */
27835
27836/* Macros for creating and checking bitmasks for character encoding.
27837 * Bit number is a bit counterintuitive, but minimizes code size.
27838 */
27839#define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \
27840 ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
27841 ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
27842 ))
27843#define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
27844
27845/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
27846DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = {
27847 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27848 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27849 DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */
27850 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
27851 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
27852 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
27853 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
27854 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
27855};
27856
27857/* E5.1 Section 15.1.3.4: uriUnescaped */
27858DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = {
27859 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27860 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27861 DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */
27862 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
27863 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
27864 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
27865 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
27866 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
27867};
27868
27869/* E5.1 Section 15.1.3.1: uriReserved + '#' */
27870DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = {
27871 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27872 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27873 DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */
27874 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
27875 DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
27876 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
27877 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
27878 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
27879};
27880
27881/* E5.1 Section 15.1.3.2: empty */
27882DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
27883 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27884 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27885 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */
27886 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
27887 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
27888 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
27889 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
27890 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
27891};
27892
27893#ifdef DUK_USE_SECTION_B
27894/* E5.1 Section B.2.2, step 7. */
27895DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
27896 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27897 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27898 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */
27899 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
27900 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
27901 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
27902 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
27903 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */
27904};
27905#endif /* DUK_USE_SECTION_B */
27906
27907#undef DUK__MKBITS
27908
27909typedef struct {
27910 duk_hthread *thr;
27911 duk_hstring *h_str;
27912 duk_bufwriter_ctx bw;
27913 const duk_uint8_t *p;
27914 const duk_uint8_t *p_start;
27915 const duk_uint8_t *p_end;
27916} duk__transform_context;
27917
27918typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp);
27919
27920/* XXX: refactor and share with other code */
27921DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) {
27922 duk_small_int_t ch;
27923 duk_small_int_t t = 0;
27924
27925 while (n > 0) {
27926 t = t * 16;
27927 ch = (duk_small_int_t) duk_hex_dectab[*p++];
27928 if (DUK_LIKELY(ch >= 0)) {
27929 t += ch;
27930 } else {
27931 return -1;
27932 }
27933 n--;
27934 }
27935 return t;
27936}
27937
27938DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) {
27939 duk_hthread *thr = (duk_hthread *) ctx;
27940 duk__transform_context tfm_ctx_alloc;
27941 duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
27942 duk_codepoint_t cp;
27943
27944 tfm_ctx->thr = thr;
27945
27946 tfm_ctx->h_str = duk_to_hstring(ctx, 0);
27947 DUK_ASSERT(tfm_ctx->h_str != NULL);
27948
27949 DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
27950
27951 tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
27952 tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
27953 tfm_ctx->p = tfm_ctx->p_start;
27954
27955 while (tfm_ctx->p < tfm_ctx->p_end) {
27956 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
27957 callback(tfm_ctx, udata, cp);
27958 }
27959
27960 DUK_BW_COMPACT(thr, &tfm_ctx->bw);
27961
27962 duk_to_string(ctx, -1);
27963 return 1;
27964}
27965
27966DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
27967 duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
27968 duk_small_int_t len;
27969 duk_codepoint_t cp1, cp2;
27970 duk_small_int_t i, t;
27971 const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata;
27972
27973 /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
27974 * Codepoint range is restricted so this is a slightly too large
27975 * but doesn't matter.
27976 */
27977 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH);
27978
27979 if (cp < 0) {
27980 goto uri_error;
27981 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
27982 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
27983 return;
27984 } else if (cp >= 0xdc00L && cp <= 0xdfffL) {
27985 goto uri_error;
27986 } else if (cp >= 0xd800L && cp <= 0xdbffL) {
27987 /* Needs lookahead */
27988 if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) {
27989 goto uri_error;
27990 }
27991 if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
27992 goto uri_error;
27993 }
27994 cp1 = cp;
27995 cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
27996 } else if (cp > 0x10ffffL) {
27997 /* Although we can allow non-BMP characters (they'll decode
27998 * back into surrogate pairs), we don't allow extended UTF-8
27999 * characters; they would encode to URIs which won't decode
28000 * back because of strict UTF-8 checks in URI decoding.
28001 * (However, we could just as well allow them here.)
28002 */
28003 goto uri_error;
28004 } else {
28005 /* Non-BMP characters within valid UTF-8 range: encode as is.
28006 * They'll decode back into surrogate pairs if the escaped
28007 * output is decoded.
28008 */
28009 ;
28010 }
28011
28012 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
28013 for (i = 0; i < len; i++) {
28014 t = (int) xutf8_buf[i];
28015 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
28016 &tfm_ctx->bw,
28017 DUK_ASC_PERCENT,
28018 (duk_uint8_t) duk_uc_nybbles[t >> 4],
28019 (duk_uint8_t) duk_uc_nybbles[t & 0x0f]);
28020 }
28021
28022 return;
28023
28024 uri_error:
28025 DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
28026}
28027
28028DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
28029 const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata;
28030 duk_small_uint_t utf8_blen;
28031 duk_codepoint_t min_cp;
28032 duk_small_int_t t; /* must be signed */
28033 duk_small_uint_t i;
28034
28035 /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
28036 * percent escape path writes max two times CESU-8 encoded BMP length.
28037 */
28038 DUK_BW_ENSURE(tfm_ctx->thr,
28039 &tfm_ctx->bw,
28040 (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ?
28041 DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH));
28042
28043 if (cp == (duk_codepoint_t) '%') {
28044 const duk_uint8_t *p = tfm_ctx->p;
28045 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
28046
28047 DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left));
28048
28049 if (left < 2) {
28050 goto uri_error;
28051 }
28052
28053 t = duk__decode_hex_escape(p, 2);
28054 DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t));
28055 if (t < 0) {
28056 goto uri_error;
28057 }
28058
28059 if (t < 0x80) {
28060 if (DUK__CHECK_BITMASK(reserved_table, t)) {
28061 /* decode '%xx' to '%xx' if decoded char in reserved set */
28062 DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
28063 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
28064 &tfm_ctx->bw,
28065 DUK_ASC_PERCENT,
28066 p[0],
28067 p[1]);
28068 } else {
28069 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t);
28070 }
28071 tfm_ctx->p += 2;
28072 return;
28073 }
28074
28075 /* Decode UTF-8 codepoint from a sequence of hex escapes. The
28076 * first byte of the sequence has been decoded to 't'.
28077 *
28078 * Note that UTF-8 validation must be strict according to the
28079 * specification: E5.1 Section 15.1.3, decode algorithm step
28080 * 4.d.vii.8. URIError from non-shortest encodings is also
28081 * specifically noted in the spec.
28082 */
28083
28084 DUK_ASSERT(t >= 0x80);
28085 if (t < 0xc0) {
28086 /* continuation byte */
28087 goto uri_error;
28088 } else if (t < 0xe0) {
28089 /* 110x xxxx; 2 bytes */
28090 utf8_blen = 2;
28091 min_cp = 0x80L;
28092 cp = t & 0x1f;
28093 } else if (t < 0xf0) {
28094 /* 1110 xxxx; 3 bytes */
28095 utf8_blen = 3;
28096 min_cp = 0x800L;
28097 cp = t & 0x0f;
28098 } else if (t < 0xf8) {
28099 /* 1111 0xxx; 4 bytes */
28100 utf8_blen = 4;
28101 min_cp = 0x10000L;
28102 cp = t & 0x07;
28103 } else {
28104 /* extended utf-8 not allowed for URIs */
28105 goto uri_error;
28106 }
28107
28108 if (left < utf8_blen * 3 - 1) {
28109 /* '%xx%xx...%xx', p points to char after first '%' */
28110 goto uri_error;
28111 }
28112
28113 p += 3;
28114 for (i = 1; i < utf8_blen; i++) {
28115 /* p points to digit part ('%xy', p points to 'x') */
28116 t = duk__decode_hex_escape(p, 2);
28117 DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx",
28118 (long) i, (long) utf8_blen, (long) cp, (unsigned long) t));
28119 if (t < 0) {
28120 goto uri_error;
28121 }
28122 if ((t & 0xc0) != 0x80) {
28123 goto uri_error;
28124 }
28125 cp = (cp << 6) + (t & 0x3f);
28126 p += 3;
28127 }
28128 p--; /* p overshoots */
28129 tfm_ctx->p = p;
28130
28131 DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp));
28132
28133 if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
28134 goto uri_error;
28135 }
28136
28137 /* The E5.1 algorithm checks whether or not a decoded codepoint
28138 * is below 0x80 and perhaps may be in the "reserved" set.
28139 * This seems pointless because the single byte UTF-8 case is
28140 * handled separately, and non-shortest encodings are rejected.
28141 * So, 'cp' cannot be below 0x80 here, and thus cannot be in
28142 * the reserved set.
28143 */
28144
28145 /* utf-8 validation ensures these */
28146 DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
28147
28148 if (cp >= 0x10000L) {
28149 cp -= 0x10000L;
28150 DUK_ASSERT(cp < 0x100000L);
28151
28152 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
28153 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L));
28154 } else {
28155 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
28156 }
28157 } else {
28158 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
28159 }
28160 return;
28161
28162 uri_error:
28163 DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
28164}
28165
28166#ifdef DUK_USE_SECTION_B
28167DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
28168 DUK_UNREF(udata);
28169
28170 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
28171
28172 if (cp < 0) {
28173 goto esc_error;
28174 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
28175 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
28176 } else if (cp < 0x100L) {
28177 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
28178 &tfm_ctx->bw,
28179 (duk_uint8_t) DUK_ASC_PERCENT,
28180 (duk_uint8_t) duk_uc_nybbles[cp >> 4],
28181 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
28182 } else if (cp < 0x10000L) {
28183 DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr,
28184 &tfm_ctx->bw,
28185 (duk_uint8_t) DUK_ASC_PERCENT,
28186 (duk_uint8_t) DUK_ASC_LC_U,
28187 (duk_uint8_t) duk_uc_nybbles[cp >> 12],
28188 (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f],
28189 (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f],
28190 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
28191 } else {
28192 /* Characters outside BMP cannot be escape()'d. We could
28193 * encode them as surrogate pairs (for codepoints inside
28194 * valid UTF-8 range, but not extended UTF-8). Because
28195 * escape() and unescape() are legacy functions, we don't.
28196 */
28197 goto esc_error;
28198 }
28199
28200 return;
28201
28202 esc_error:
28203 DUK_ERROR_TYPE(tfm_ctx->thr, "invalid input");
28204}
28205
28206DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
28207 duk_small_int_t t;
28208
28209 DUK_UNREF(udata);
28210
28211 if (cp == (duk_codepoint_t) '%') {
28212 const duk_uint8_t *p = tfm_ctx->p;
28213 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
28214
28215 if (left >= 5 && p[0] == 'u' &&
28216 ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
28217 cp = (duk_codepoint_t) t;
28218 tfm_ctx->p += 5;
28219 } else if (left >= 2 &&
28220 ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
28221 cp = (duk_codepoint_t) t;
28222 tfm_ctx->p += 2;
28223 }
28224 }
28225
28226 DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
28227}
28228#endif /* DUK_USE_SECTION_B */
28229
28230/*
28231 * Eval
28232 *
28233 * Eval needs to handle both a "direct eval" and an "indirect eval".
28234 * Direct eval handling needs access to the caller's activation so that its
28235 * lexical environment can be accessed. A direct eval is only possible from
28236 * Ecmascript code; an indirect eval call is possible also from C code.
28237 * When an indirect eval call is made from C code, there may not be a
28238 * calling activation at all which needs careful handling.
28239 */
28240
28241DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
28242 duk_hthread *thr = (duk_hthread *) ctx;
28243 duk_hstring *h;
28244 duk_activation *act_caller;
28245 duk_activation *act_eval;
28246 duk_activation *act;
28247 duk_hcompiledfunction *func;
28248 duk_hobject *outer_lex_env;
28249 duk_hobject *outer_var_env;
28250 duk_bool_t this_to_global = 1;
28251 duk_small_uint_t comp_flags;
28252 duk_int_t level = -2;
28253
28254 DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
28255 DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
28256 DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
28257 (thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
28258
28259 /*
28260 * callstack_top - 1 --> this function
28261 * callstack_top - 2 --> caller (may not exist)
28262 *
28263 * If called directly from C, callstack_top might be 1. If calling
28264 * activation doesn't exist, call must be indirect.
28265 */
28266
28267 h = duk_get_hstring(ctx, 0);
28268 if (!h) {
28269 return 1; /* return arg as-is */
28270 }
28271
28272#if defined(DUK_USE_DEBUGGER_SUPPORT)
28273 /* NOTE: level is used only by the debugger and should never be present
28274 * for an Ecmascript eval().
28275 */
28276 DUK_ASSERT(level == -2); /* by default, use caller's environment */
28277 if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) {
28278 level = duk_get_int(ctx, 1);
28279 }
28280 DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
28281#endif
28282
28283 /* [ source ] */
28284
28285 comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
28286 act_eval = thr->callstack + thr->callstack_top - 1; /* this function */
28287 if (thr->callstack_top >= (duk_size_t) -level) {
28288 /* Have a calling activation, check for direct eval (otherwise
28289 * assume indirect eval.
28290 */
28291 act_caller = thr->callstack + thr->callstack_top + level; /* caller */
28292 if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
28293 (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
28294 /* Only direct eval inherits strictness from calling code
28295 * (E5.1 Section 10.1.1).
28296 */
28297 comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
28298 }
28299 } else {
28300 DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
28301 }
28302 act_caller = NULL; /* avoid dereference after potential callstack realloc */
28303 act_eval = NULL;
28304
28305 duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
28306 duk_js_compile(thr,
28307 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
28308 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
28309 comp_flags);
28310 func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
28311 DUK_ASSERT(func != NULL);
28312 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
28313
28314 /* [ source template ] */
28315
28316 /* E5 Section 10.4.2 */
28317 DUK_ASSERT(thr->callstack_top >= 1);
28318 act = thr->callstack + thr->callstack_top - 1; /* this function */
28319 if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
28320 DUK_ASSERT(thr->callstack_top >= 2);
28321 act = thr->callstack + thr->callstack_top + level; /* caller */
28322 if (act->lex_env == NULL) {
28323 DUK_ASSERT(act->var_env == NULL);
28324 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
28325
28326 /* this may have side effects, so re-lookup act */
28327 duk_js_init_activation_environment_records_delayed(thr, act);
28328 act = thr->callstack + thr->callstack_top + level;
28329 }
28330 DUK_ASSERT(act->lex_env != NULL);
28331 DUK_ASSERT(act->var_env != NULL);
28332
28333 this_to_global = 0;
28334
28335 if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
28336 duk_hobject *new_env;
28337 duk_hobject *act_lex_env;
28338
28339 DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
28340 "var_env and lex_env to a fresh env, "
28341 "this_binding to caller's this_binding"));
28342
28343 act_lex_env = act->lex_env;
28344 act = NULL; /* invalidated */
28345
28346 (void) duk_push_object_helper_proto(ctx,
28347 DUK_HOBJECT_FLAG_EXTENSIBLE |
28348 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
28349 act_lex_env);
28350 new_env = duk_require_hobject(ctx, -1);
28351 DUK_ASSERT(new_env != NULL);
28352 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO",
28353 (duk_heaphdr *) new_env));
28354
28355 outer_lex_env = new_env;
28356 outer_var_env = new_env;
28357
28358 duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
28359
28360 /* compiler's responsibility */
28361 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
28362 } else {
28363 DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
28364 "var_env and lex_env to caller's envs, "
28365 "this_binding to caller's this_binding"));
28366
28367 outer_lex_env = act->lex_env;
28368 outer_var_env = act->var_env;
28369
28370 /* compiler's responsibility */
28371 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
28372 }
28373 } else {
28374 DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
28375 "global object, this_binding to global object"));
28376
28377 this_to_global = 1;
28378 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
28379 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
28380 }
28381 act = NULL;
28382
28383 /* Eval code doesn't need an automatic .prototype object. */
28384 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
28385
28386 /* [ source template closure ] */
28387
28388 if (this_to_global) {
28389 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
28390 duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
28391 } else {
28392 duk_tval *tv;
28393 DUK_ASSERT(thr->callstack_top >= 2);
28394 act = thr->callstack + thr->callstack_top + level; /* caller */
28395 tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
28396 DUK_ASSERT(tv >= thr->valstack);
28397 duk_push_tval(ctx, tv);
28398 }
28399
28400 DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
28401 (duk_heaphdr *) outer_lex_env,
28402 (duk_heaphdr *) outer_var_env,
28403 duk_get_tval(ctx, -1)));
28404
28405 /* [ source template closure this ] */
28406
28407 duk_call_method(ctx, 0);
28408
28409 /* [ source template result ] */
28410
28411 return 1;
28412}
28413
28414/*
28415 * Parsing of ints and floats
28416 */
28417
28418DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
28419 duk_int32_t radix;
28420 duk_small_uint_t s2n_flags;
28421
28422 DUK_ASSERT_TOP(ctx, 2);
28423 duk_to_string(ctx, 0);
28424
28425 radix = duk_to_int32(ctx, 1);
28426
28427 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
28428 DUK_S2N_FLAG_ALLOW_GARBAGE |
28429 DUK_S2N_FLAG_ALLOW_PLUS |
28430 DUK_S2N_FLAG_ALLOW_MINUS |
28431 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
28432 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
28433
28434 /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
28435 *
28436 * Don't autodetect octals (from leading zeroes), require user code to
28437 * provide an explicit radix 8 for parsing octal. See write-up from Mozilla:
28438 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
28439 */
28440
28441 if (radix != 0) {
28442 if (radix < 2 || radix > 36) {
28443 goto ret_nan;
28444 }
28445 if (radix != 16) {
28446 s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
28447 }
28448 } else {
28449 radix = 10;
28450 }
28451
28452 duk_dup(ctx, 0);
28453 duk_numconv_parse(ctx, radix, s2n_flags);
28454 return 1;
28455
28456 ret_nan:
28457 duk_push_nan(ctx);
28458 return 1;
28459}
28460
28461DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
28462 duk_small_uint_t s2n_flags;
28463 duk_int32_t radix;
28464
28465 DUK_ASSERT_TOP(ctx, 1);
28466 duk_to_string(ctx, 0);
28467
28468 radix = 10;
28469
28470 /* XXX: check flags */
28471 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
28472 DUK_S2N_FLAG_ALLOW_EXP |
28473 DUK_S2N_FLAG_ALLOW_GARBAGE |
28474 DUK_S2N_FLAG_ALLOW_PLUS |
28475 DUK_S2N_FLAG_ALLOW_MINUS |
28476 DUK_S2N_FLAG_ALLOW_INF |
28477 DUK_S2N_FLAG_ALLOW_FRAC |
28478 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
28479 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
28480 DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
28481
28482 duk_numconv_parse(ctx, radix, s2n_flags);
28483 return 1;
28484}
28485
28486/*
28487 * Number checkers
28488 */
28489
28490DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) {
28491 duk_double_t d = duk_to_number(ctx, 0);
28492 duk_push_boolean(ctx, DUK_ISNAN(d));
28493 return 1;
28494}
28495
28496DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
28497 duk_double_t d = duk_to_number(ctx, 0);
28498 duk_push_boolean(ctx, DUK_ISFINITE(d));
28499 return 1;
28500}
28501
28502/*
28503 * URI handling
28504 */
28505
28506DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
28507 return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
28508}
28509
28510DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) {
28511 return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
28512}
28513
28514DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) {
28515 return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
28516}
28517
28518DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) {
28519 return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
28520}
28521
28522#ifdef DUK_USE_SECTION_B
28523DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
28524 return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
28525}
28526
28527DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
28528 return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL);
28529}
28530#else /* DUK_USE_SECTION_B */
28531DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
28532 DUK_UNREF(ctx);
28533 return DUK_RET_UNSUPPORTED_ERROR;
28534}
28535
28536DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
28537 DUK_UNREF(ctx);
28538 return DUK_RET_UNSUPPORTED_ERROR;
28539}
28540#endif /* DUK_USE_SECTION_B */
28541
28542#if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT))
28543DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
28544 duk_hthread *thr = (duk_hthread *) ctx;
28545 duk_int_t magic;
28546 duk_idx_t nargs;
28547 const duk_uint8_t *buf;
28548 duk_size_t sz_buf;
28549 const char nl = (const char) DUK_ASC_LF;
28550#ifndef DUK_USE_PREFER_SIZE
28551 duk_uint8_t buf_stack[256];
28552#endif
28553#ifdef DUK_USE_FILE_IO
28554 duk_file *f_out;
28555#endif
28556
28557 DUK_UNREF(thr);
28558
28559 magic = duk_get_current_magic(ctx);
28560 DUK_UNREF(magic);
28561
28562 nargs = duk_get_top(ctx);
28563
28564 /* If argument count is 1 and first argument is a buffer, write the buffer
28565 * as raw data into the file without a newline; this allows exact control
28566 * over stdout/stderr without an additional entrypoint (useful for now).
28567 *
28568 * Otherwise current print/alert semantics are to ToString() coerce
28569 * arguments, join them with a single space, and append a newline.
28570 */
28571
28572 if (nargs == 1 && duk_is_buffer(ctx, 0)) {
28573 buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf);
28574 DUK_ASSERT(buf != NULL);
28575 } else if (nargs > 0) {
28576#ifdef DUK_USE_PREFER_SIZE
28577 /* Compact but lots of churn. */
28578 duk_push_hstring_stridx(thr, DUK_STRIDX_SPACE);
28579 duk_insert(ctx, 0);
28580 duk_join(ctx, nargs);
28581 duk_push_string(thr, "\n");
28582 duk_concat(ctx, 2);
28583 buf = (const duk_uint8_t *) duk_get_lstring(ctx, -1, &sz_buf);
28584 DUK_ASSERT(buf != NULL);
28585#else /* DUK_USE_PREFER_SIZE */
28586 /* Higher footprint, less churn. */
28587 duk_idx_t i;
28588 duk_size_t sz_str;
28589 const duk_uint8_t *p_str;
28590 duk_uint8_t *p;
28591
28592 sz_buf = (duk_size_t) nargs; /* spaces (nargs - 1) + newline */
28593 for (i = 0; i < nargs; i++) {
28594 (void) duk_to_lstring(ctx, i, &sz_str);
28595 sz_buf += sz_str;
28596 }
28597
28598 if (sz_buf <= sizeof(buf_stack)) {
28599 p = (duk_uint8_t *) buf_stack;
28600 } else {
28601 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf);
28602 DUK_ASSERT(p != NULL);
28603 }
28604
28605 buf = (const duk_uint8_t *) p;
28606 for (i = 0; i < nargs; i++) {
28607 p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str);
28608 DUK_ASSERT(p_str != NULL);
28609 DUK_MEMCPY((void *) p, (const void *) p_str, sz_str);
28610 p += sz_str;
28611 *p++ = (duk_uint8_t) (i == nargs - 1 ? DUK_ASC_LF : DUK_ASC_SPACE);
28612 }
28613 DUK_ASSERT((const duk_uint8_t *) p == buf + sz_buf);
28614#endif /* DUK_USE_PREFER_SIZE */
28615 } else {
28616 buf = (const duk_uint8_t *) &nl;
28617 sz_buf = 1;
28618 }
28619
28620 /* 'buf' contains the string to write, 'sz_buf' contains the length
28621 * (which may be zero).
28622 */
28623 DUK_ASSERT(buf != NULL);
28624
28625 if (sz_buf == 0) {
28626 return 0;
28627 }
28628
28629#ifdef DUK_USE_FILE_IO
28630 f_out = (magic ? DUK_STDERR : DUK_STDOUT);
28631 DUK_FWRITE((const void *) buf, 1, (size_t) sz_buf, f_out);
28632 DUK_FFLUSH(f_out);
28633#endif
28634
28635#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT)
28636 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
28637 duk_debug_write_notify(thr, magic ? DUK_DBG_CMD_ALERT : DUK_DBG_CMD_PRINT);
28638 duk_debug_write_string(thr, (const char *) buf, sz_buf);
28639 duk_debug_write_eom(thr);
28640 }
28641#endif
28642 return 0;
28643}
28644#elif defined(DUK_USE_BROWSER_LIKE) /* print provider */
28645DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
28646 DUK_UNREF(ctx);
28647 return 0;
28648}
28649#else /* print provider */
28650DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
28651 DUK_UNREF(ctx);
28652 return DUK_RET_UNSUPPORTED_ERROR;
28653}
28654#endif /* print provider */
28655
28656/*
28657 * CommonJS require() and modules support
28658 */
28659
28660#if defined(DUK_USE_COMMONJS_MODULES)
28661DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) {
28662 duk_hthread *thr = (duk_hthread *) ctx;
28663 duk_uint8_t buf[DUK_BI_COMMONJS_MODULE_ID_LIMIT];
28664 duk_uint8_t *p;
28665 duk_uint8_t *q;
28666 duk_uint8_t *q_last; /* last component */
28667 duk_int_t int_rc;
28668
28669 DUK_ASSERT(req_id != NULL);
28670 /* mod_id may be NULL */
28671
28672 /*
28673 * A few notes on the algorithm:
28674 *
28675 * - Terms are not allowed to begin with a period unless the term
28676 * is either '.' or '..'. This simplifies implementation (and
28677 * is within CommonJS modules specification).
28678 *
28679 * - There are few output bound checks here. This is on purpose:
28680 * the resolution input is length checked and the output is never
28681 * longer than the input. The resolved output is written directly
28682 * over the input because it's never longer than the input at any
28683 * point in the algorithm.
28684 *
28685 * - Non-ASCII characters are processed as individual bytes and
28686 * need no special treatment. However, U+0000 terminates the
28687 * algorithm; this is not an issue because U+0000 is not a
28688 * desirable term character anyway.
28689 */
28690
28691 /*
28692 * Set up the resolution input which is the requested ID directly
28693 * (if absolute or no current module path) or with current module
28694 * ID prepended (if relative and current module path exists).
28695 *
28696 * Suppose current module is 'foo/bar' and relative path is './quux'.
28697 * The 'bar' component must be replaced so the initial input here is
28698 * 'foo/bar/.././quux'.
28699 */
28700
28701 if (mod_id != NULL && req_id[0] == '.') {
28702 int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id);
28703 } else {
28704 int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s", req_id);
28705 }
28706 if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) {
28707 /* Potentially truncated, NUL not guaranteed in any case.
28708 * The (int_rc < 0) case should not occur in practice.
28709 */
28710 DUK_DD(DUK_DDPRINT("resolve error: temporary working module ID doesn't fit into resolve buffer"));
28711 goto resolve_error;
28712 }
28713 DUK_ASSERT(DUK_STRLEN((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */
28714
28715 DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf));
28716
28717 /*
28718 * Resolution loop. At the top of the loop we're expecting a valid
28719 * term: '.', '..', or a non-empty identifier not starting with a period.
28720 */
28721
28722 p = buf;
28723 q = buf;
28724 for (;;) {
28725 duk_uint_fast8_t c;
28726
28727 /* Here 'p' always points to the start of a term.
28728 *
28729 * We can also unconditionally reset q_last here: if this is
28730 * the last (non-empty) term q_last will have the right value
28731 * on loop exit.
28732 */
28733
28734 DUK_ASSERT(p >= q); /* output is never longer than input during resolution */
28735
28736 DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf=%p",
28737 (const char *) p, (void *) q, (void *) buf));
28738
28739 q_last = q;
28740
28741 c = *p++;
28742 if (DUK_UNLIKELY(c == 0)) {
28743 DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term"));
28744 goto resolve_error;
28745 } else if (DUK_UNLIKELY(c == '.')) {
28746 c = *p++;
28747 if (c == '/') {
28748 /* Term was '.' and is eaten entirely (including dup slashes). */
28749 goto eat_dup_slashes;
28750 }
28751 if (c == '.' && *p == '/') {
28752 /* Term was '..', backtrack resolved name by one component.
28753 * q[-1] = previous slash (or beyond start of buffer)
28754 * q[-2] = last char of previous component (or beyond start of buffer)
28755 */
28756 p++; /* eat (first) input slash */
28757 DUK_ASSERT(q >= buf);
28758 if (q == buf) {
28759 DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack"));
28760 goto resolve_error;
28761 }
28762 DUK_ASSERT(*(q - 1) == '/');
28763 q--; /* backtrack to last output slash (dups already eliminated) */
28764 for (;;) {
28765 /* Backtrack to previous slash or start of buffer. */
28766 DUK_ASSERT(q >= buf);
28767 if (q == buf) {
28768 break;
28769 }
28770 if (*(q - 1) == '/') {
28771 break;
28772 }
28773 q--;
28774 }
28775 goto eat_dup_slashes;
28776 }
28777 DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)"));
28778 goto resolve_error;
28779 } else if (DUK_UNLIKELY(c == '/')) {
28780 /* e.g. require('/foo'), empty terms not allowed */
28781 DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)"));
28782 goto resolve_error;
28783 } else {
28784 for (;;) {
28785 /* Copy term name until end or '/'. */
28786 *q++ = c;
28787 c = *p++;
28788 if (DUK_UNLIKELY(c == 0)) {
28789 /* This was the last term, and q_last was
28790 * updated to match this term at loop top.
28791 */
28792 goto loop_done;
28793 } else if (DUK_UNLIKELY(c == '/')) {
28794 *q++ = '/';
28795 break;
28796 } else {
28797 /* write on next loop */
28798 }
28799 }
28800 }
28801
28802 eat_dup_slashes:
28803 for (;;) {
28804 /* eat dup slashes */
28805 c = *p;
28806 if (DUK_LIKELY(c != '/')) {
28807 break;
28808 }
28809 p++;
28810 }
28811 }
28812 loop_done:
28813 /* Output #1: resolved absolute name */
28814 DUK_ASSERT(q >= buf);
28815 duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
28816
28817 /* Output #2: last component name */
28818 DUK_ASSERT(q >= q_last);
28819 DUK_ASSERT(q_last >= buf);
28820 duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last));
28821
28822 DUK_DD(DUK_DDPRINT("after resolving module name: buf=%p, q_last=%p, q=%p",
28823 (void *) buf, (void *) q_last, (void *) q));
28824 return;
28825
28826 resolve_error:
28827 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id);
28828}
28829#endif /* DUK_USE_COMMONJS_MODULES */
28830
28831#if defined(DUK_USE_COMMONJS_MODULES)
28832/* Stack indices for better readability */
28833#define DUK__IDX_REQUESTED_ID 0 /* Module id requested */
28834#define DUK__IDX_REQUIRE 1 /* Current require() function */
28835#define DUK__IDX_REQUIRE_ID 2 /* The base ID of the current require() function, resolution base */
28836#define DUK__IDX_RESOLVED_ID 3 /* Resolved, normalized absolute module ID */
28837#define DUK__IDX_LASTCOMP 4 /* Last component name in resolved path */
28838#define DUK__IDX_DUKTAPE 5 /* Duktape object */
28839#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */
28840#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */
28841#define DUK__IDX_FRESH_REQUIRE 8 /* New require() function for module, updated resolution base */
28842#define DUK__IDX_EXPORTS 9 /* Default exports table */
28843#define DUK__IDX_MODULE 10 /* Module object containing module.exports, etc */
28844
28845DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
28846 const char *str_req_id; /* requested identifier */
28847 const char *str_mod_id; /* require.id of current module */
28848 duk_int_t pcall_rc;
28849
28850 /* NOTE: we try to minimize code size by avoiding unnecessary pops,
28851 * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP()
28852 * assertions are used to ensure stack configuration is correct at each
28853 * step.
28854 */
28855
28856 /*
28857 * Resolve module identifier into canonical absolute form.
28858 */
28859
28860 str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID);
28861 duk_push_current_function(ctx);
28862 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ID);
28863 str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */
28864 DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T",
28865 duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
28866 duk_get_tval(ctx, DUK__IDX_REQUIRE_ID)));
28867 duk__bi_global_resolve_module_id(ctx, str_req_id, str_mod_id);
28868 str_req_id = NULL;
28869 str_mod_id = NULL;
28870 DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T, lastcomp=%!T",
28871 duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
28872 duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
28873 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
28874 duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
28875
28876 /* [ requested_id require require.id resolved_id last_comp ] */
28877 DUK_ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1);
28878
28879 /*
28880 * Cached module check.
28881 *
28882 * If module has been loaded or its loading has already begun without
28883 * finishing, return the same cached value ('exports'). The value is
28884 * registered when module load starts so that circular references can
28885 * be supported to some extent.
28886 */
28887
28888 duk_push_hobject_bidx(ctx, DUK_BIDX_DUKTAPE);
28889 duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_LOADED); /* Duktape.modLoaded */
28890 (void) duk_require_hobject(ctx, DUK__IDX_MODLOADED);
28891 DUK_ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1);
28892
28893 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28894 if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) {
28895 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */
28896 DUK_DD(DUK_DDPRINT("module already loaded: %!T",
28897 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID)));
28898 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_EXPORTS); /* return module.exports */
28899 return 1;
28900 }
28901 DUK_ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1);
28902
28903 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */
28904
28905 /*
28906 * Module not loaded (and loading not started previously).
28907 *
28908 * Create a new require() function with 'id' set to resolved ID
28909 * of module being loaded. Also create 'exports' and 'module'
28910 * tables but don't register exports to the loaded table yet.
28911 * We don't want to do that unless the user module search callbacks
28912 * succeeds in finding the module.
28913 */
28914
28915 DUK_D(DUK_DPRINT("loading module %!T, resolution base %!T, requested ID %!T -> resolved ID %!T, last component %!T",
28916 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
28917 duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
28918 duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
28919 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
28920 duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
28921
28922 /* Fresh require: require.id is left configurable (but not writable)
28923 * so that is not easy to accidentally tweak it, but it can still be
28924 * done with Object.defineProperty().
28925 *
28926 * XXX: require.id could also be just made non-configurable, as there
28927 * is no practical reason to touch it.
28928 */
28929 duk_push_c_function(ctx, duk_bi_global_object_require, 1 /*nargs*/);
28930 duk_push_hstring_stridx(ctx, DUK_STRIDX_REQUIRE);
28931 duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
28932 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28933 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 */
28934
28935 /* Module table:
28936 * - module.exports: initial exports table (may be replaced by user)
28937 * - module.id is non-writable and non-configurable, as the CommonJS
28938 * spec suggests this if possible
28939 * - module.filename: not set, defaults to resolved ID if not explicitly
28940 * set by modSearch() (note capitalization, not .fileName, matches Node.js)
28941 * - module.name: not set, defaults to last component of resolved ID if
28942 * not explicitly set by modSearch()
28943 */
28944 duk_push_object(ctx); /* exports */
28945 duk_push_object(ctx); /* module */
28946 duk_dup(ctx, DUK__IDX_EXPORTS);
28947 duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS, DUK_PROPDESC_FLAGS_WC); /* module.exports = exports */
28948 duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */
28949 duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_NONE); /* module.id = resolved_id */
28950 duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */
28951 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 1);
28952
28953 DUK_DD(DUK_DDPRINT("module table created: %!T", duk_get_tval(ctx, DUK__IDX_MODULE)));
28954
28955 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */
28956
28957 /* Register the module table early to modLoaded[] so that we can
28958 * support circular references even in modSearch(). If an error
28959 * is thrown, we'll delete the reference.
28960 */
28961 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28962 duk_dup(ctx, DUK__IDX_MODULE);
28963 duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */
28964
28965 /*
28966 * Call user provided module search function and build the wrapped
28967 * module source code (if necessary). The module search function
28968 * can be used to implement pure Ecmacsript, pure C, and mixed
28969 * Ecmascript/C modules.
28970 *
28971 * The module search function can operate on the exports table directly
28972 * (e.g. DLL code can register values to it). It can also return a
28973 * string which is interpreted as module source code (if a non-string
28974 * is returned the module is assumed to be a pure C one). If a module
28975 * cannot be found, an error must be thrown by the user callback.
28976 *
28977 * Because Duktape.modLoaded[] already contains the module being
28978 * loaded, circular references for C modules should also work
28979 * (although expected to be quite rare).
28980 */
28981
28982 duk_push_string(ctx, "(function(require,exports,module){");
28983
28984 /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */
28985 duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_SEARCH); /* Duktape.modSearch */
28986 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28987 duk_dup(ctx, DUK__IDX_FRESH_REQUIRE);
28988 duk_dup(ctx, DUK__IDX_EXPORTS);
28989 duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */
28990 pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */
28991 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 3);
28992
28993 if (pcall_rc != DUK_EXEC_SUCCESS) {
28994 /* Delete entry in Duktape.modLoaded[] and rethrow. */
28995 goto delete_rethrow;
28996 }
28997
28998 /* If user callback did not return source code, module loading
28999 * is finished (user callback initialized exports table directly).
29000 */
29001 if (!duk_is_string(ctx, -1)) {
29002 /* User callback did not return source code, so module loading
29003 * is finished: just update modLoaded with final module.exports
29004 * and we're done.
29005 */
29006 goto return_exports;
29007 }
29008
29009 /* Finish the wrapped module source. Force module.filename as the
29010 * function .fileName so it gets set for functions defined within a
29011 * module. This also ensures loggers created within the module get
29012 * the module ID (or overridden filename) as their default logger name.
29013 * (Note capitalization: .filename matches Node.js while .fileName is
29014 * used elsewhere in Duktape.)
29015 */
29016 duk_push_string(ctx, "\n})"); /* Newline allows module last line to contain a // comment. */
29017 duk_concat(ctx, 3);
29018 if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_FILENAME)) {
29019 /* module.filename for .fileName, default to resolved ID if
29020 * not present.
29021 */
29022 duk_pop(ctx);
29023 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
29024 }
29025 duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL);
29026
29027 /* Module has now evaluated to a wrapped module function. Force its
29028 * .name to match module.name (defaults to last component of resolved
29029 * ID) so that it is shown in stack traces too. Note that we must not
29030 * introduce an actual name binding into the function scope (which is
29031 * usually the case with a named function) because it would affect the
29032 * scope seen by the module and shadow accesses to globals of the same name.
29033 * This is now done by compiling the function as anonymous and then forcing
29034 * its .name without setting a "has name binding" flag.
29035 */
29036
29037 duk_push_hstring_stridx(ctx, DUK_STRIDX_NAME);
29038 if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_NAME)) {
29039 /* module.name for .name, default to last component if
29040 * not present.
29041 */
29042 duk_pop(ctx);
29043 duk_dup(ctx, DUK__IDX_LASTCOMP);
29044 }
29045 duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
29046
29047 /*
29048 * Call the wrapped module function.
29049 *
29050 * Use a protected call so that we can update Duktape.modLoaded[resolved_id]
29051 * even if the module throws an error.
29052 */
29053
29054 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */
29055 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
29056
29057 duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */
29058 duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */
29059 duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); /* relookup exports from module.exports in case it was changed by modSearch */
29060 duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */
29061 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 6);
29062
29063 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */
29064
29065 pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/);
29066 if (pcall_rc != DUK_EXEC_SUCCESS) {
29067 /* Module loading failed. Node.js will forget the module
29068 * registration so that another require() will try to load
29069 * the module again. Mimic that behavior.
29070 */
29071 goto delete_rethrow;
29072 }
29073
29074 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */
29075 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
29076
29077 /* fall through */
29078
29079 return_exports:
29080 duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS);
29081 duk_compact(ctx, -1); /* compact the exports table */
29082 return 1; /* return module.exports */
29083
29084 delete_rethrow:
29085 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
29086 duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */
29087 duk_throw(ctx); /* rethrow original error */
29088 return 0; /* not reachable */
29089}
29090
29091#undef DUK__IDX_REQUESTED_ID
29092#undef DUK__IDX_REQUIRE
29093#undef DUK__IDX_REQUIRE_ID
29094#undef DUK__IDX_RESOLVED_ID
29095#undef DUK__IDX_LASTCOMP
29096#undef DUK__IDX_DUKTAPE
29097#undef DUK__IDX_MODLOADED
29098#undef DUK__IDX_UNDEFINED
29099#undef DUK__IDX_FRESH_REQUIRE
29100#undef DUK__IDX_EXPORTS
29101#undef DUK__IDX_MODULE
29102#else
29103DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
29104 DUK_UNREF(ctx);
29105 return DUK_RET_UNSUPPORTED_ERROR;
29106}
29107#endif /* DUK_USE_COMMONJS_MODULES */
29108#line 1 "duk_bi_json.c"
29109/*
29110 * JSON built-ins.
29111 *
29112 * See doc/json.rst.
29113 *
29114 * Codepoints are handled as duk_uint_fast32_t to ensure that the full
29115 * unsigned 32-bit range is supported. This matters to e.g. JX.
29116 *
29117 * Input parsing doesn't do an explicit end-of-input check at all. This is
29118 * safe: input string data is always NUL-terminated (0x00) and valid JSON
29119 * inputs never contain plain NUL characters, so that as long as syntax checks
29120 * are correct, we'll never read past the NUL. This approach reduces code size
29121 * and improves parsing performance, but it's critical that syntax checks are
29122 * indeed correct!
29123 */
29124
29125/* include removed: duk_internal.h */
29126
29127/*
29128 * Local defines and forward declarations.
29129 */
29130
29131#define DUK__JSON_DECSTR_BUFSIZE 128
29132#define DUK__JSON_DECSTR_CHUNKSIZE 64
29133#define DUK__JSON_ENCSTR_CHUNKSIZE 64
29134#define DUK__JSON_STRINGIFY_BUFSIZE 128
29135#define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */
29136
29137DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
29138DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
29139DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
29140DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
29141DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
29142DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
29143DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
29144DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
29145#ifdef DUK_USE_JX
29146DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
29147DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
29148DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
29149#endif
29150DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx);
29151DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx);
29152DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx);
29153DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx);
29154DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx);
29155DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx);
29156DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx);
29157
29158DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch);
29159DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2);
29160DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx);
29161DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h);
29162#if defined(DUK_USE_FASTINT)
29163DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
29164#endif
29165DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx);
29166DUK_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);
29167DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
29168DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
29169DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
29170DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
29171DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx);
29172DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx);
29173DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
29174DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv);
29175DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
29176#if defined(DUK_USE_FASTINT)
29177DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
29178#endif
29179#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
29180DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
29181DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
29182DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj);
29183#endif
29184DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
29185
29186/*
29187 * Helper tables
29188 */
29189
29190#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
29191DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = {
29192 /* 0x00 ... 0x7f: as is
29193 * 0x80: escape generically
29194 * 0x81: slow path
29195 * 0xa0 ... 0xff: backslash + one char
29196 */
29197
29198 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80,
29199 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
29200 0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
29201 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
29202 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
29203 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f,
29204 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
29205 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81,
29206 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29207 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29208 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29209 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29210 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29211 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29212 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29213 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81
29214};
29215#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
29216DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = {
29217 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
29218 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
29219 DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL,
29220 DUK_ASC_LC_F, DUK_ASC_LC_R
29221};
29222#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
29223
29224#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
29225DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = {
29226 /* 0x00: slow path
29227 * other: as is
29228 */
29229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29231 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
29232 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
29233 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
29234 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f,
29235 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
29236 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
29237 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
29238 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
29239 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
29240 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
29241 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
29242 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
29243 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
29244 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
29245};
29246#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
29247
29248#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
29249DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = {
29250 /* 0x00: finish (non-white)
29251 * 0x01: continue
29252 */
29253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
29254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29255 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
29269};
29270#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
29271
29272#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
29273DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = {
29274 /* 0x00: finish (not part of number)
29275 * 0x01: continue
29276 */
29277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29278 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00,
29280 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29281 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29283 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
29293};
29294#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
29295
29296/*
29297 * Parsing implementation.
29298 *
29299 * JSON lexer is now separate from duk_lexer.c because there are numerous
29300 * small differences making it difficult to share the lexer.
29301 *
29302 * The parser here works with raw bytes directly; this works because all
29303 * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values
29304 * inside strings will be passed on without normalization; this is not a
29305 * compliance concern because compliant inputs will always be valid
29306 * CESU-8 encodings.
29307 */
29308
29309DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
29310 /* Shared handler to minimize parser size. Cause will be
29311 * hidden, unfortunately, but we'll have an offset which
29312 * is often quite enough.
29313 */
29314 DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON,
29315 (long) (js_ctx->p - js_ctx->p_start));
29316}
29317
29318DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
29319 const duk_uint8_t *p;
29320 duk_uint8_t t;
29321
29322 p = js_ctx->p;
29323 for (;;) {
29324 DUK_ASSERT(p <= js_ctx->p_end);
29325 t = *p;
29326
29327#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
29328 /* This fast path is pretty marginal in practice.
29329 * XXX: candidate for removal.
29330 */
29331 DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */
29332 if (duk__json_eatwhite_lookup[t] == 0) {
29333 break;
29334 }
29335#else /* DUK_USE_JSON_EATWHITE_FASTPATH */
29336 if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) {
29337 /* NUL also comes here. Comparison order matters, 0x20
29338 * is most common whitespace.
29339 */
29340 break;
29341 }
29342#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
29343 p++;
29344 }
29345 js_ctx->p = p;
29346}
29347
29348DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
29349 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
29350 return *js_ctx->p;
29351}
29352
29353DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
29354 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
29355 return *js_ctx->p++;
29356}
29357
29358DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
29359 duk__dec_eat_white(js_ctx);
29360 return duk__dec_get(js_ctx);
29361}
29362
29363/* For JX, expressing the whole unsigned 32-bit range matters. */
29364DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
29365 duk_small_uint_t i;
29366 duk_uint_fast32_t res = 0;
29367 duk_uint8_t x;
29368 duk_small_int_t t;
29369
29370 for (i = 0; i < n; i++) {
29371 /* XXX: share helper from lexer; duk_lexer.c / hexval(). */
29372
29373 x = duk__dec_get(js_ctx);
29374 DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld",
29375 (long) i, (long) n, (long) res, (long) x));
29376
29377 /* x == 0x00 (EOF) causes syntax_error */
29378 DUK_ASSERT(duk_hex_dectab[0] == -1);
29379 t = duk_hex_dectab[x & 0xff];
29380 if (DUK_LIKELY(t >= 0)) {
29381 res = (res * 16) + t;
29382 } else {
29383 /* catches EOF and invalid digits */
29384 goto syntax_error;
29385 }
29386 }
29387
29388 DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res));
29389 return res;
29390
29391 syntax_error:
29392 duk__dec_syntax_error(js_ctx);
29393 DUK_UNREACHABLE();
29394 return 0;
29395}
29396
29397DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
29398 duk_hstring *h;
29399 const duk_uint8_t *p;
29400 duk_uint8_t x, y;
29401
29402 /* First character has already been eaten and checked by the caller.
29403 * We can scan until a NUL in stridx string because no built-in strings
29404 * have internal NULs.
29405 */
29406
29407 DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
29408 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
29409 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
29410 DUK_ASSERT(h != NULL);
29411
29412 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
29413 DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */
29414
29415 for (;;) {
29416 x = *p;
29417 if (x == 0) {
29418 break;
29419 }
29420 y = duk__dec_get(js_ctx);
29421 if (x != y) {
29422 /* Catches EOF of JSON input. */
29423 goto syntax_error;
29424 }
29425 p++;
29426 }
29427
29428 return;
29429
29430 syntax_error:
29431 duk__dec_syntax_error(js_ctx);
29432 DUK_UNREACHABLE();
29433}
29434
29435DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
29436 duk_uint_fast32_t cp;
29437
29438 /* EOF (-1) will be cast to an unsigned value first
29439 * and then re-cast for the switch. In any case, it
29440 * will match the default case (syntax error).
29441 */
29442 cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
29443 switch ((int) cp) {
29444 case DUK_ASC_BACKSLASH: break;
29445 case DUK_ASC_DOUBLEQUOTE: break;
29446 case DUK_ASC_SLASH: break;
29447 case DUK_ASC_LC_T: cp = 0x09; break;
29448 case DUK_ASC_LC_N: cp = 0x0a; break;
29449 case DUK_ASC_LC_R: cp = 0x0d; break;
29450 case DUK_ASC_LC_F: cp = 0x0c; break;
29451 case DUK_ASC_LC_B: cp = 0x08; break;
29452 case DUK_ASC_LC_U: {
29453 cp = duk__dec_decode_hex_escape(js_ctx, 4);
29454 break;
29455 }
29456#ifdef DUK_USE_JX
29457 case DUK_ASC_UC_U: {
29458 if (js_ctx->flag_ext_custom) {
29459 cp = duk__dec_decode_hex_escape(js_ctx, 8);
29460 } else {
29461 return 1; /* syntax error */
29462 }
29463 break;
29464 }
29465 case DUK_ASC_LC_X: {
29466 if (js_ctx->flag_ext_custom) {
29467 cp = duk__dec_decode_hex_escape(js_ctx, 2);
29468 } else {
29469 return 1; /* syntax error */
29470 }
29471 break;
29472 }
29473#endif /* DUK_USE_JX */
29474 default:
29475 /* catches EOF (0x00) */
29476 return 1; /* syntax error */
29477 }
29478
29479 DUK_RAW_WRITE_XUTF8(*ext_p, cp);
29480
29481 return 0;
29482}
29483
29484DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
29485 duk_hthread *thr = js_ctx->thr;
29486 duk_context *ctx = (duk_context *) thr;
29487 duk_bufwriter_ctx bw_alloc;
29488 duk_bufwriter_ctx *bw;
29489 duk_uint8_t *q;
29490
29491 /* '"' was eaten by caller */
29492
29493 /* Note that we currently parse -bytes-, not codepoints.
29494 * All non-ASCII extended UTF-8 will encode to bytes >= 0x80,
29495 * so they'll simply pass through (valid UTF-8 or not).
29496 */
29497
29498 bw = &bw_alloc;
29499 DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE);
29500 q = DUK_BW_GET_PTR(js_ctx->thr, bw);
29501
29502#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
29503 for (;;) {
29504 duk_small_uint_t safe;
29505 duk_uint8_t b, x;
29506 const duk_uint8_t *p;
29507
29508 /* Select a safe loop count where no output checks are
29509 * needed assuming we won't encounter escapes. Input
29510 * bound checks are not necessary as a NUL (guaranteed)
29511 * will cause a SyntaxError before we read out of bounds.
29512 */
29513
29514 safe = DUK__JSON_DECSTR_CHUNKSIZE;
29515
29516 /* Ensure space for 1:1 output plus one escape. */
29517 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q);
29518
29519 p = js_ctx->p; /* temp copy, write back for next loop */
29520 for (;;) {
29521 if (safe == 0) {
29522 js_ctx->p = p;
29523 break;
29524 }
29525 safe--;
29526
29527 /* End of input (NUL) goes through slow path and causes SyntaxError. */
29528 DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00);
29529
29530 b = *p++;
29531 x = (duk_small_int_t) duk__json_decstr_lookup[b];
29532 if (DUK_LIKELY(x != 0)) {
29533 /* Fast path, decode as is. */
29534 *q++ = b;
29535 } else if (b == DUK_ASC_DOUBLEQUOTE) {
29536 js_ctx->p = p;
29537 goto found_quote;
29538 } else if (b == DUK_ASC_BACKSLASH) {
29539 /* We've ensured space for one escaped input; then
29540 * bail out and recheck (this makes escape handling
29541 * quite slow but it's uncommon).
29542 */
29543 js_ctx->p = p;
29544 if (duk__dec_string_escape(js_ctx, &q) != 0) {
29545 goto syntax_error;
29546 }
29547 break;
29548 } else {
29549 js_ctx->p = p;
29550 goto syntax_error;
29551 }
29552 }
29553 }
29554 found_quote:
29555#else /* DUK_USE_JSON_DECSTRING_FASTPATH */
29556 for (;;) {
29557 duk_uint8_t x;
29558
29559 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q);
29560
29561 x = duk__dec_get(js_ctx);
29562
29563 if (x == DUK_ASC_DOUBLEQUOTE) {
29564 break;
29565 } else if (x == DUK_ASC_BACKSLASH) {
29566 if (duk__dec_string_escape(js_ctx, &q) != 0) {
29567 goto syntax_error;
29568 }
29569 } else if (x < 0x20) {
29570 /* catches EOF (NUL) */
29571 goto syntax_error;
29572 } else {
29573 *q++ = (duk_uint8_t) x;
29574 }
29575 }
29576#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
29577
29578 DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
29579 duk_to_string(ctx, -1);
29580
29581 /* [ ... str ] */
29582
29583 return;
29584
29585 syntax_error:
29586 duk__dec_syntax_error(js_ctx);
29587 DUK_UNREACHABLE();
29588}
29589
29590#ifdef DUK_USE_JX
29591/* Decode a plain string consisting entirely of identifier characters.
29592 * Used to parse plain keys (e.g. "foo: 123").
29593 */
29594DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
29595 duk_hthread *thr = js_ctx->thr;
29596 duk_context *ctx = (duk_context *) thr;
29597 const duk_uint8_t *p;
29598 duk_small_int_t x;
29599
29600 /* Caller has already eaten the first char so backtrack one byte. */
29601
29602 js_ctx->p--; /* safe */
29603 p = js_ctx->p;
29604
29605 /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of
29606 * parsing (which is correct except if there are non-shortest encodings).
29607 * There is also no need to check explicitly for end of input buffer as
29608 * the input is NUL padded and NUL will exit the parsing loop.
29609 *
29610 * Because no unescaping takes place, we can just scan to the end of the
29611 * plain string and intern from the input buffer.
29612 */
29613
29614 for (;;) {
29615 x = *p;
29616
29617 /* There is no need to check the first character specially here
29618 * (i.e. reject digits): the caller only accepts valid initial
29619 * characters and won't call us if the first character is a digit.
29620 * This also ensures that the plain string won't be empty.
29621 */
29622
29623 if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) {
29624 break;
29625 }
29626 p++;
29627 }
29628
29629 duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
29630 js_ctx->p = p;
29631
29632 /* [ ... str ] */
29633}
29634#endif /* DUK_USE_JX */
29635
29636#ifdef DUK_USE_JX
29637DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
29638 duk_hthread *thr = js_ctx->thr;
29639 duk_context *ctx = (duk_context *) thr;
29640 const duk_uint8_t *p;
29641 duk_small_int_t x;
29642 void *voidptr;
29643
29644 /* Caller has already eaten the first character ('(') which we don't need. */
29645
29646 p = js_ctx->p;
29647
29648 for (;;) {
29649 x = *p;
29650
29651 /* Assume that the native representation never contains a closing
29652 * parenthesis.
29653 */
29654
29655 if (x == DUK_ASC_RPAREN) {
29656 break;
29657 } else if (x <= 0) {
29658 /* NUL term or -1 (EOF), NUL check would suffice */
29659 goto syntax_error;
29660 }
29661 p++;
29662 }
29663
29664 /* There is no need to NUL delimit the sscanf() call: trailing garbage is
29665 * ignored and there is always a NUL terminator which will force an error
29666 * if no error is encountered before it. It's possible that the scan
29667 * would scan further than between [js_ctx->p,p[ though and we'd advance
29668 * by less than the scanned value.
29669 *
29670 * Because pointers are platform specific, a failure to scan a pointer
29671 * results in a null pointer which is a better placeholder than a missing
29672 * value or an error.
29673 */
29674
29675 voidptr = NULL;
29676 (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
29677 duk_push_pointer(ctx, voidptr);
29678 js_ctx->p = p + 1; /* skip ')' */
29679
29680 /* [ ... ptr ] */
29681
29682 return;
29683
29684 syntax_error:
29685 duk__dec_syntax_error(js_ctx);
29686 DUK_UNREACHABLE();
29687}
29688#endif /* DUK_USE_JX */
29689
29690#ifdef DUK_USE_JX
29691DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
29692 duk_hthread *thr = js_ctx->thr;
29693 duk_context *ctx = (duk_context *) thr;
29694 const duk_uint8_t *p;
29695 duk_uint8_t *buf;
29696 duk_size_t src_len;
29697 duk_small_int_t x;
29698
29699 /* Caller has already eaten the first character ('|') which we don't need. */
29700
29701 p = js_ctx->p;
29702
29703 /* XXX: Would be nice to share the fast path loop from duk_hex_decode()
29704 * and avoid creating a temporary buffer. However, there are some
29705 * differences which prevent trivial sharing:
29706 *
29707 * - Pipe char detection
29708 * - EOF detection
29709 * - Unknown length of input and output
29710 *
29711 * The best approach here would be a bufwriter and a reasonaly sized
29712 * safe inner loop (e.g. 64 output bytes at a time).
29713 */
29714
29715 for (;;) {
29716 x = *p;
29717
29718 /* This loop intentionally does not ensure characters are valid
29719 * ([0-9a-fA-F]) because the hex decode call below will do that.
29720 */
29721 if (x == DUK_ASC_PIPE) {
29722 break;
29723 } else if (x <= 0) {
29724 /* NUL term or -1 (EOF), NUL check would suffice */
29725 goto syntax_error;
29726 }
29727 p++;
29728 }
29729
29730 src_len = (duk_size_t) (p - js_ctx->p);
29731 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len);
29732 DUK_ASSERT(buf != NULL);
29733 DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
29734 duk_hex_decode(ctx, -1);
29735
29736 js_ctx->p = p + 1; /* skip '|' */
29737
29738 /* [ ... buf ] */
29739
29740 return;
29741
29742 syntax_error:
29743 duk__dec_syntax_error(js_ctx);
29744 DUK_UNREACHABLE();
29745}
29746#endif /* DUK_USE_JX */
29747
29748/* Parse a number, other than NaN or +/- Infinity */
29749DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
29750 duk_context *ctx = (duk_context *) js_ctx->thr;
29751 const duk_uint8_t *p_start;
29752 const duk_uint8_t *p;
29753 duk_uint8_t x;
29754 duk_small_uint_t s2n_flags;
29755
29756 DUK_DDD(DUK_DDDPRINT("parse_number"));
29757
29758 p_start = js_ctx->p;
29759
29760 /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a
29761 * string for strict number parsing.
29762 */
29763
29764 p = js_ctx->p;
29765 for (;;) {
29766 x = *p;
29767
29768 DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld",
29769 (const void *) p_start, (const void *) p,
29770 (const void *) js_ctx->p_end, (long) x));
29771
29772#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
29773 /* This fast path is pretty marginal in practice.
29774 * XXX: candidate for removal.
29775 */
29776 DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */
29777 if (duk__json_decnumber_lookup[x] == 0) {
29778 break;
29779 }
29780#else /* DUK_USE_JSON_DECNUMBER_FASTPATH */
29781 if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
29782 (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E ||
29783 x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) {
29784 /* Plus sign must be accepted for positive exponents
29785 * (e.g. '1.5e+2'). This clause catches NULs.
29786 */
29787 break;
29788 }
29789#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
29790 p++; /* safe, because matched (NUL causes a break) */
29791 }
29792 js_ctx->p = p;
29793
29794 DUK_ASSERT(js_ctx->p > p_start);
29795 duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start));
29796
29797 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
29798 DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
29799 DUK_S2N_FLAG_ALLOW_FRAC;
29800
29801 DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
29802 (duk_tval *) duk_get_tval(ctx, -1)));
29803 duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
29804 if (duk_is_nan(ctx, -1)) {
29805 duk__dec_syntax_error(js_ctx);
29806 }
29807 DUK_ASSERT(duk_is_number(ctx, -1));
29808 DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
29809 (duk_tval *) duk_get_tval(ctx, -1)));
29810
29811 /* [ ... num ] */
29812}
29813
29814DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
29815 duk_context *ctx = (duk_context *) js_ctx->thr;
29816 duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
29817
29818 /* c recursion check */
29819
29820 DUK_ASSERT(js_ctx->recursion_depth >= 0);
29821 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
29822 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
29823 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT);
29824 }
29825 js_ctx->recursion_depth++;
29826}
29827
29828DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
29829 /* c recursion check */
29830
29831 DUK_ASSERT(js_ctx->recursion_depth > 0);
29832 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
29833 js_ctx->recursion_depth--;
29834}
29835
29836DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
29837 duk_context *ctx = (duk_context *) js_ctx->thr;
29838 duk_int_t key_count; /* XXX: a "first" flag would suffice */
29839 duk_uint8_t x;
29840
29841 DUK_DDD(DUK_DDDPRINT("parse_object"));
29842
29843 duk__dec_objarr_entry(js_ctx);
29844
29845 duk_push_object(ctx);
29846
29847 /* Initial '{' has been checked and eaten by caller. */
29848
29849 key_count = 0;
29850 for (;;) {
29851 x = duk__dec_get_nonwhite(js_ctx);
29852
29853 DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
29854 (duk_tval *) duk_get_tval(ctx, -1),
29855 (long) x, (long) key_count));
29856
29857 /* handle comma and closing brace */
29858
29859 if (x == DUK_ASC_COMMA && key_count > 0) {
29860 /* accept comma, expect new value */
29861 x = duk__dec_get_nonwhite(js_ctx);
29862 } else if (x == DUK_ASC_RCURLY) {
29863 /* eat closing brace */
29864 break;
29865 } else if (key_count == 0) {
29866 /* accept anything, expect first value (EOF will be
29867 * caught by key parsing below.
29868 */
29869 ;
29870 } else {
29871 /* catches EOF (NUL) and initial comma */
29872 goto syntax_error;
29873 }
29874
29875 /* parse key and value */
29876
29877 if (x == DUK_ASC_DOUBLEQUOTE) {
29878 duk__dec_string(js_ctx);
29879#ifdef DUK_USE_JX
29880 } else if (js_ctx->flag_ext_custom &&
29881 duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
29882 duk__dec_plain_string(js_ctx);
29883#endif
29884 } else {
29885 goto syntax_error;
29886 }
29887
29888 /* [ ... obj key ] */
29889
29890 x = duk__dec_get_nonwhite(js_ctx);
29891 if (x != DUK_ASC_COLON) {
29892 goto syntax_error;
29893 }
29894
29895 duk__dec_value(js_ctx);
29896
29897 /* [ ... obj key val ] */
29898
29899 duk_xdef_prop_wec(ctx, -3);
29900
29901 /* [ ... obj ] */
29902
29903 key_count++;
29904 }
29905
29906 /* [ ... obj ] */
29907
29908 DUK_DDD(DUK_DDDPRINT("parse_object: final object 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_array(duk_json_dec_ctx *js_ctx) {
29920 duk_context *ctx = (duk_context *) js_ctx->thr;
29921 duk_uarridx_t arr_idx;
29922 duk_uint8_t x;
29923
29924 DUK_DDD(DUK_DDDPRINT("parse_array"));
29925
29926 duk__dec_objarr_entry(js_ctx);
29927
29928 duk_push_array(ctx);
29929
29930 /* Initial '[' has been checked and eaten by caller. */
29931
29932 arr_idx = 0;
29933 for (;;) {
29934 x = duk__dec_get_nonwhite(js_ctx);
29935
29936 DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
29937 (duk_tval *) duk_get_tval(ctx, -1),
29938 (long) x, (long) arr_idx));
29939
29940 /* handle comma and closing bracket */
29941
29942 if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) {
29943 /* accept comma, expect new value */
29944 ;
29945 } else if (x == DUK_ASC_RBRACKET) {
29946 /* eat closing bracket */
29947 break;
29948 } else if (arr_idx == 0) {
29949 /* accept anything, expect first value (EOF will be
29950 * caught by duk__dec_value() below.
29951 */
29952 js_ctx->p--; /* backtrack (safe) */
29953 } else {
29954 /* catches EOF (NUL) and initial comma */
29955 goto syntax_error;
29956 }
29957
29958 /* parse value */
29959
29960 duk__dec_value(js_ctx);
29961
29962 /* [ ... arr val ] */
29963
29964 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
29965 arr_idx++;
29966 }
29967
29968 /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to
29969 * set the values.
29970 */
29971
29972 duk_set_length(ctx, -1, arr_idx);
29973
29974 /* [ ... arr ] */
29975
29976 DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
29977 (duk_tval *) duk_get_tval(ctx, -1)));
29978
29979 duk__dec_objarr_exit(js_ctx);
29980 return;
29981
29982 syntax_error:
29983 duk__dec_syntax_error(js_ctx);
29984 DUK_UNREACHABLE();
29985}
29986
29987DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
29988 duk_context *ctx = (duk_context *) js_ctx->thr;
29989 duk_uint8_t x;
29990
29991 x = duk__dec_get_nonwhite(js_ctx);
29992
29993 DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x));
29994
29995 /* Note: duk__dec_req_stridx() backtracks one char */
29996
29997 if (x == DUK_ASC_DOUBLEQUOTE) {
29998 duk__dec_string(js_ctx);
29999 } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
30000#ifdef DUK_USE_JX
30001 if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
30002 duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
30003 duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
30004 } else {
30005#else
30006 { /* unconditional block */
30007#endif
30008 /* We already ate 'x', so backup one byte. */
30009 js_ctx->p--; /* safe */
30010 duk__dec_number(js_ctx);
30011 }
30012 } else if (x == DUK_ASC_LC_T) {
30013 duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
30014 duk_push_true(ctx);
30015 } else if (x == DUK_ASC_LC_F) {
30016 duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
30017 duk_push_false(ctx);
30018 } else if (x == DUK_ASC_LC_N) {
30019 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
30020 duk_push_null(ctx);
30021#ifdef DUK_USE_JX
30022 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
30023 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
30024 duk_push_undefined(ctx);
30025 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
30026 duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
30027 duk_push_nan(ctx);
30028 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
30029 duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
30030 duk_push_number(ctx, DUK_DOUBLE_INFINITY);
30031 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
30032 duk__dec_pointer(js_ctx);
30033 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
30034 duk__dec_buffer(js_ctx);
30035#endif
30036 } else if (x == DUK_ASC_LCURLY) {
30037 duk__dec_object(js_ctx);
30038 } else if (x == DUK_ASC_LBRACKET) {
30039 duk__dec_array(js_ctx);
30040 } else {
30041 /* catches EOF (NUL) */
30042 goto syntax_error;
30043 }
30044
30045 duk__dec_eat_white(js_ctx);
30046
30047 /* [ ... val ] */
30048 return;
30049
30050 syntax_error:
30051 duk__dec_syntax_error(js_ctx);
30052 DUK_UNREACHABLE();
30053}
30054
30055/* Recursive value reviver, implements the Walk() algorithm. No C recursion
30056 * check is done here because the initial parsing step will already ensure
30057 * there is a reasonable limit on C recursion depth and hence object depth.
30058 */
30059DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
30060 duk_context *ctx = (duk_context *) js_ctx->thr;
30061 duk_hobject *h;
30062 duk_uarridx_t i, arr_len;
30063
30064 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
30065 (long) duk_get_top(ctx),
30066 (duk_tval *) duk_get_tval(ctx, -2),
30067 (duk_tval *) duk_get_tval(ctx, -1)));
30068
30069 duk_dup_top(ctx);
30070 duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */
30071
30072 h = duk_get_hobject(ctx, -1);
30073 if (h != NULL) {
30074 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
30075 arr_len = (duk_uarridx_t) duk_get_length(ctx, -1);
30076 for (i = 0; i < arr_len; i++) {
30077 /* [ ... holder name val ] */
30078
30079 DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
30080 (long) duk_get_top(ctx), (long) i, (long) arr_len,
30081 (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
30082 (duk_tval *) duk_get_tval(ctx, -1)));
30083
30084 /* XXX: push_uint_string / push_u32_string */
30085 duk_dup_top(ctx);
30086 duk_push_uint(ctx, (duk_uint_t) i);
30087 duk_to_string(ctx, -1); /* -> [ ... holder name val val ToString(i) ] */
30088 duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
30089
30090 if (duk_is_undefined(ctx, -1)) {
30091 duk_pop(ctx);
30092 duk_del_prop_index(ctx, -1, i);
30093 } else {
30094 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
30095 * here but it currently makes some assumptions that might
30096 * not hold (e.g. that previous property is not an accessor).
30097 */
30098 duk_put_prop_index(ctx, -2, i);
30099 }
30100 }
30101 } else {
30102 /* [ ... holder name val ] */
30103 duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
30104 while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
30105 DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
30106 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5),
30107 (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3),
30108 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
30109
30110 /* [ ... holder name val enum obj_key ] */
30111 duk_dup(ctx, -3);
30112 duk_dup(ctx, -2);
30113
30114 /* [ ... holder name val enum obj_key val obj_key ] */
30115 duk__dec_reviver_walk(js_ctx);
30116
30117 /* [ ... holder name val enum obj_key new_elem ] */
30118 if (duk_is_undefined(ctx, -1)) {
30119 duk_pop(ctx);
30120 duk_del_prop(ctx, -3);
30121 } else {
30122 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
30123 * here but it currently makes some assumptions that might
30124 * not hold (e.g. that previous property is not an accessor).
30125 *
30126 * Using duk_put_prop() works incorrectly with '__proto__'
30127 * if the own property with that name has been deleted. This
30128 * does not happen normally, but a clever reviver can trigger
30129 * that, see complex reviver case in: test-bug-json-parse-__proto__.js.
30130 */
30131 duk_put_prop(ctx, -4);
30132 }
30133 }
30134 duk_pop(ctx); /* pop enum */
30135 }
30136 }
30137
30138 /* [ ... holder name val ] */
30139
30140 duk_dup(ctx, js_ctx->idx_reviver);
30141 duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */
30142 duk_call_method(ctx, 2); /* -> [ ... res ] */
30143
30144 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
30145 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1)));
30146}
30147
30148/*
30149 * Stringify implementation.
30150 */
30151
30152#define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch))
30153#define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2))
30154#define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h))
30155#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
30156#define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p))
30157#endif
30158#define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i))
30159#define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx))
30160
30161DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) {
30162 DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch);
30163}
30164
30165DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) {
30166 DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2);
30167}
30168
30169DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) {
30170 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
30171}
30172
30173#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
30174DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
30175 DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str);
30176}
30177#endif
30178
30179DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
30180 duk_hstring *h;
30181
30182 DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
30183 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
30184 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
30185 DUK_ASSERT(h != NULL);
30186
30187 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
30188}
30189
30190DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) {
30191 DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1);
30192 DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1);
30193}
30194
30195#define DUK__MKESC(nybbles,esc1,esc2) \
30196 (((duk_uint_fast32_t) (nybbles)) << 16) | \
30197 (((duk_uint_fast32_t) (esc1)) << 8) | \
30198 ((duk_uint_fast32_t) (esc2))
30199
30200DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) {
30201 duk_uint_fast32_t tmp;
30202 duk_small_uint_t dig;
30203
30204 DUK_UNREF(js_ctx);
30205
30206 /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */
30207
30208 /* Select appropriate escape format automatically, and set 'tmp' to a
30209 * value encoding both the escape format character and the nybble count:
30210 *
30211 * (nybble_count << 16) | (escape_char1) | (escape_char2)
30212 */
30213
30214#ifdef DUK_USE_JX
30215 if (DUK_LIKELY(cp < 0x100UL)) {
30216 if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
30217 tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
30218 } else {
30219 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
30220 }
30221 } else
30222#endif
30223 if (DUK_LIKELY(cp < 0x10000UL)) {
30224 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
30225 } else {
30226#ifdef DUK_USE_JX
30227 if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
30228 tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
30229 } else
30230#endif
30231 {
30232 /* In compatible mode and standard JSON mode, output
30233 * something useful for non-BMP characters. This won't
30234 * roundtrip but will still be more or less readable and
30235 * more useful than an error.
30236 */
30237 tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS);
30238 }
30239 }
30240
30241 *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff);
30242 *q++ = (duk_uint8_t) (tmp & 0xff);
30243
30244 tmp = tmp >> 16;
30245 while (tmp > 0) {
30246 tmp--;
30247 dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f);
30248 *q++ = duk_lc_digits[dig];
30249 }
30250
30251 return q;
30252}
30253
30254DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
30255 const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */
30256 duk_size_t k_len;
30257 duk_codepoint_t cp;
30258
30259 DUK_ASSERT(k != NULL);
30260
30261 /* Accept ASCII strings which conform to identifier requirements
30262 * as being emitted without key quotes. Since we only accept ASCII
30263 * there's no need for actual decoding: 'p' is intentionally signed
30264 * so that bytes >= 0x80 extend to negative values and are rejected
30265 * as invalid identifier codepoints.
30266 */
30267
30268 if (js_ctx->flag_avoid_key_quotes) {
30269 k_len = DUK_HSTRING_GET_BYTELEN(k);
30270 p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k);
30271 p_end = p_start + k_len;
30272 p = p_start;
30273
30274 if (p == p_end) {
30275 /* Zero length string is not accepted without quotes */
30276 goto quote_normally;
30277 }
30278 cp = (duk_codepoint_t) (*p++);
30279 if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) {
30280 goto quote_normally;
30281 }
30282 while (p < p_end) {
30283 cp = (duk_codepoint_t) (*p++);
30284 if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) {
30285 goto quote_normally;
30286 }
30287 }
30288
30289 /* This seems faster than emitting bytes one at a time and
30290 * then potentially rewinding.
30291 */
30292 DUK__EMIT_HSTR(js_ctx, k);
30293 return;
30294 }
30295
30296 quote_normally:
30297 duk__enc_quote_string(js_ctx, k);
30298}
30299
30300/* The Quote(value) operation: quote a string.
30301 *
30302 * Stack policy: [ ] -> [ ].
30303 */
30304
30305DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
30306 duk_hthread *thr = js_ctx->thr;
30307 const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp;
30308 duk_uint8_t *q;
30309 duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */
30310
30311 DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
30312
30313 DUK_ASSERT(h_str != NULL);
30314 p_start = DUK_HSTRING_GET_DATA(h_str);
30315 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str);
30316 p = p_start;
30317
30318 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
30319
30320 /* Encode string in small chunks, estimating the maximum expansion so that
30321 * there's no need to ensure space while processing the chunk.
30322 */
30323
30324 while (p < p_end) {
30325 duk_size_t left, now, space;
30326
30327 left = (duk_size_t) (p_end - p);
30328 now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ?
30329 DUK__JSON_ENCSTR_CHUNKSIZE : left);
30330
30331 /* Maximum expansion per input byte is 6:
30332 * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6).
30333 * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3).
30334 * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5).
30335 */
30336 space = now * 6;
30337 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
30338
30339 p_now = p + now;
30340
30341 while (p < p_now) {
30342#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
30343 duk_uint8_t b;
30344
30345 b = duk__json_quotestr_lookup[*p++];
30346 if (DUK_LIKELY(b < 0x80)) {
30347 /* Most input bytes go through here. */
30348 *q++ = b;
30349 } else if (b >= 0xa0) {
30350 *q++ = DUK_ASC_BACKSLASH;
30351 *q++ = (duk_uint8_t) (b - 0x80);
30352 } else if (b == 0x80) {
30353 cp = (duk_ucodepoint_t) (*(p - 1));
30354 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30355 } else if (b == 0x7f && js_ctx->flag_ascii_only) {
30356 /* 0x7F is special */
30357 DUK_ASSERT(b == 0x81);
30358 cp = (duk_ucodepoint_t) 0x7f;
30359 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30360 } else {
30361 DUK_ASSERT(b == 0x81);
30362 p--;
30363
30364 /* slow path is shared */
30365#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
30366 cp = *p;
30367
30368 if (DUK_LIKELY(cp <= 0x7f)) {
30369 /* ascii fast path: avoid decoding utf-8 */
30370 p++;
30371 if (cp == 0x22 || cp == 0x5c) {
30372 /* double quote or backslash */
30373 *q++ = DUK_ASC_BACKSLASH;
30374 *q++ = (duk_uint8_t) cp;
30375 } else if (cp < 0x20) {
30376 duk_uint_fast8_t esc_char;
30377
30378 /* This approach is a bit shorter than a straight
30379 * if-else-ladder and also a bit faster.
30380 */
30381 if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) &&
30382 (esc_char = duk__json_quotestr_esc[cp]) != 0) {
30383 *q++ = DUK_ASC_BACKSLASH;
30384 *q++ = (duk_uint8_t) esc_char;
30385 } else {
30386 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30387 }
30388 } else if (cp == 0x7f && js_ctx->flag_ascii_only) {
30389 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30390 } else {
30391 /* any other printable -> as is */
30392 *q++ = (duk_uint8_t) cp;
30393 }
30394 } else {
30395 /* slow path is shared */
30396#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
30397
30398 /* slow path decode */
30399
30400 /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
30401 * and go forward one byte. This is of course very lossy, but allows some kind
30402 * of output to be produced even for internal strings which don't conform to
30403 * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior
30404 * does not violate the Ecmascript specification. The behavior is applied to
30405 * all modes, including Ecmascript standard JSON. Because the current XUTF-8
30406 * decoding is not very strict, this behavior only really affects initial bytes
30407 * and truncated codepoints.
30408 *
30409 * Another alternative would be to scan forwards to start of next codepoint
30410 * (or end of input) and emit just one replacement codepoint.
30411 */
30412
30413 p_tmp = p;
30414 if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
30415 /* Decode failed. */
30416 cp = *p_tmp;
30417 p = p_tmp + 1;
30418 }
30419
30420#ifdef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
30421 if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
30422#else
30423 if (js_ctx->flag_ascii_only) {
30424#endif
30425 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30426 } else {
30427 /* as is */
30428 DUK_RAW_WRITE_XUTF8(q, cp);
30429 }
30430 }
30431 }
30432
30433 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
30434 }
30435
30436 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
30437}
30438
30439/* Encode a double (checked by caller) from stack top. Stack top may be
30440 * replaced by serialized string but is not popped (caller does that).
30441 */
30442DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
30443 duk_hthread *thr;
30444 duk_context *ctx;
30445 duk_tval *tv;
30446 duk_double_t d;
30447 duk_small_int_t c;
30448 duk_small_int_t s;
30449 duk_small_uint_t stridx;
30450 duk_small_uint_t n2s_flags;
30451 duk_hstring *h_str;
30452
30453 DUK_ASSERT(js_ctx != NULL);
30454 thr = js_ctx->thr;
30455 DUK_ASSERT(thr != NULL);
30456 ctx = (duk_context *) thr;
30457
30458 /* Caller must ensure 'tv' is indeed a double and not a fastint! */
30459 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
30460 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
30461 d = DUK_TVAL_GET_DOUBLE(tv);
30462
30463 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
30464 s = (duk_small_int_t) DUK_SIGNBIT(d);
30465 DUK_UNREF(s);
30466
30467 if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) {
30468 DUK_ASSERT(DUK_ISFINITE(d));
30469
30470#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30471 /* Negative zero needs special handling in JX/JC because
30472 * it would otherwise serialize to '0', not '-0'.
30473 */
30474 if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
30475 (js_ctx->flag_ext_custom_or_compatible))) {
30476 duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
30477 } else
30478#endif /* DUK_USE_JX || DUK_USE_JC */
30479 {
30480 n2s_flags = 0;
30481 /* [ ... number ] -> [ ... string ] */
30482 duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
30483 }
30484 h_str = duk_to_hstring(ctx, -1);
30485 DUK_ASSERT(h_str != NULL);
30486 DUK__EMIT_HSTR(js_ctx, h_str);
30487 return;
30488 }
30489
30490#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30491 if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
30492 DUK_JSON_FLAG_EXT_COMPATIBLE))) {
30493 stridx = DUK_STRIDX_LC_NULL;
30494 } else if (c == DUK_FP_NAN) {
30495 stridx = js_ctx->stridx_custom_nan;
30496 } else if (s == 0) {
30497 stridx = js_ctx->stridx_custom_posinf;
30498 } else {
30499 stridx = js_ctx->stridx_custom_neginf;
30500 }
30501#else
30502 stridx = DUK_STRIDX_LC_NULL;
30503#endif
30504 DUK__EMIT_STRIDX(js_ctx, stridx);
30505}
30506
30507#if defined(DUK_USE_FASTINT)
30508/* Encode a fastint from duk_tval ptr, no value stack effects. */
30509DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
30510 duk_int64_t v;
30511
30512 /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328
30513 * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808
30514 * (20 chars long). Alloc space for 64-bit range to be safe.
30515 */
30516 duk_uint8_t buf[20 + 1];
30517
30518 /* Caller must ensure 'tv' is indeed a fastint! */
30519 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
30520 v = DUK_TVAL_GET_FASTINT(tv);
30521
30522 /* XXX: There are no format strings in duk_config.h yet, could add
30523 * one for formatting duk_int64_t. For now, assumes "%lld" and that
30524 * "long long" type exists. Could also rely on C99 directly but that
30525 * won't work for older MSVC.
30526 */
30527 DUK_SPRINTF((char *) buf, "%lld", (long long) v);
30528 DUK__EMIT_CSTR(js_ctx, (const char *) buf);
30529}
30530#endif
30531
30532#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30533#if defined(DUK_USE_HEX_FASTPATH)
30534DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
30535 duk_uint8_t *q;
30536 duk_uint16_t *q16;
30537 duk_small_uint_t x;
30538 duk_size_t i, len_safe;
30539#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
30540 duk_bool_t shift_dst;
30541#endif
30542
30543 /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
30544 * For platforms where unaligned accesses are not allowed, shift 'dst'
30545 * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result
30546 * in place. The faster encoding loop makes up the difference.
30547 * There's always space for one extra byte because a terminator always
30548 * follows the hex data and that's been accounted for by the caller.
30549 */
30550
30551#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
30552 q16 = (duk_uint16_t *) (void *) dst;
30553#else
30554 shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U);
30555 if (shift_dst) {
30556 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1"));
30557 q16 = (duk_uint16_t *) (void *) (dst + 1);
30558 } else {
30559 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned"));
30560 q16 = (duk_uint16_t *) (void *) dst;
30561 }
30562 DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0);
30563#endif
30564
30565 len_safe = src_len & ~0x03U;
30566 for (i = 0; i < len_safe; i += 4) {
30567 q16[0] = duk_hex_enctab[src[i]];
30568 q16[1] = duk_hex_enctab[src[i + 1]];
30569 q16[2] = duk_hex_enctab[src[i + 2]];
30570 q16[3] = duk_hex_enctab[src[i + 3]];
30571 q16 += 4;
30572 }
30573 q = (duk_uint8_t *) q16;
30574
30575#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
30576 if (shift_dst) {
30577 q--;
30578 DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe);
30579 DUK_ASSERT(dst + 2 * len_safe == q);
30580 }
30581#endif
30582
30583 for (; i < src_len; i++) {
30584 x = src[i];
30585 *q++ = duk_lc_digits[x >> 4];
30586 *q++ = duk_lc_digits[x & 0x0f];
30587 }
30588
30589 return q;
30590}
30591#else /* DUK_USE_HEX_FASTPATH */
30592DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
30593 const duk_uint8_t *p;
30594 const duk_uint8_t *p_end;
30595 duk_uint8_t *q;
30596 duk_small_uint_t x;
30597
30598 p = src;
30599 p_end = src + src_len;
30600 q = dst;
30601 while (p != p_end) {
30602 x = *p++;
30603 *q++ = duk_lc_digits[x >> 4];
30604 *q++ = duk_lc_digits[x & 0x0f];
30605 }
30606
30607 return q;
30608}
30609#endif /* DUK_USE_HEX_FASTPATH */
30610
30611DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
30612 duk_hthread *thr;
30613 duk_uint8_t *q;
30614 duk_size_t space;
30615
30616 thr = js_ctx->thr;
30617
30618 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
30619 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
30620
30621 /* Buffer values are encoded in (lowercase) hex to make the
30622 * binary data readable. Base64 or similar would be more
30623 * compact but less readable, and the point of JX/JC
30624 * variants is to be as useful to a programmer as possible.
30625 */
30626
30627 /* The #ifdef clutter here needs to handle the three cases:
30628 * (1) JX+JC, (2) JX only, (3) JC only.
30629 */
30630
30631 /* Note: space must cater for both JX and JC. */
30632 space = 9 + buf_len * 2 + 2;
30633 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
30634 DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */
30635 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
30636
30637#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30638 if (js_ctx->flag_ext_custom)
30639#endif
30640#if defined(DUK_USE_JX)
30641 {
30642 *q++ = DUK_ASC_PIPE;
30643 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
30644 *q++ = DUK_ASC_PIPE;
30645
30646 }
30647#endif
30648#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30649 else
30650#endif
30651#if defined(DUK_USE_JC)
30652 {
30653 DUK_ASSERT(js_ctx->flag_ext_compatible);
30654 DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */
30655 q += 9;
30656 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
30657 *q++ = DUK_ASC_DOUBLEQUOTE;
30658 *q++ = DUK_ASC_RCURLY;
30659 }
30660#endif
30661
30662 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
30663}
30664
30665DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
30666 duk__enc_buffer_data(js_ctx,
30667 (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
30668 (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
30669}
30670#endif /* DUK_USE_JX || DUK_USE_JC */
30671
30672#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30673DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
30674 char buf[64]; /* XXX: how to figure correct size? */
30675 const char *fmt;
30676
30677 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
30678 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
30679
30680 DUK_MEMZERO(buf, sizeof(buf));
30681
30682 /* The #ifdef clutter here needs to handle the three cases:
30683 * (1) JX+JC, (2) JX only, (3) JC only.
30684 */
30685#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30686 if (js_ctx->flag_ext_custom)
30687#endif
30688#if defined(DUK_USE_JX)
30689 {
30690 fmt = ptr ? "(%p)" : "(null)";
30691 }
30692#endif
30693#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30694 else
30695#endif
30696#if defined(DUK_USE_JC)
30697 {
30698 DUK_ASSERT(js_ctx->flag_ext_compatible);
30699 fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
30700 }
30701#endif
30702
30703 /* When ptr == NULL, the format argument is unused. */
30704 DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */
30705 DUK__EMIT_CSTR(js_ctx, buf);
30706}
30707#endif /* DUK_USE_JX || DUK_USE_JC */
30708
30709#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30710DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) {
30711 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
30712
30713 if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
30714 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
30715 } else {
30716 /* Handle both full and partial slice (as long as covered). */
30717 duk__enc_buffer_data(js_ctx,
30718 (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
30719 (duk_size_t) h_bufobj->length);
30720 }
30721}
30722#endif /* DUK_USE_JX || DUK_USE_JC */
30723
30724/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
30725 * directly related to indent depth.
30726 */
30727#if defined(DUK_USE_PREFER_SIZE)
30728DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
30729 DUK_ASSERT(js_ctx->h_gap != NULL);
30730 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
30731
30732 DUK__EMIT_1(js_ctx, 0x0a);
30733 while (depth-- > 0) {
30734 DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap);
30735 }
30736}
30737#else /* DUK_USE_PREFER_SIZE */
30738DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
30739 const duk_uint8_t *gap_data;
30740 duk_size_t gap_len;
30741 duk_size_t avail_bytes; /* bytes of indent available for copying */
30742 duk_size_t need_bytes; /* bytes of indent still needed */
30743 duk_uint8_t *p_start;
30744 duk_uint8_t *p;
30745
30746 DUK_ASSERT(js_ctx->h_gap != NULL);
30747 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
30748
30749 DUK__EMIT_1(js_ctx, 0x0a);
30750 if (DUK_UNLIKELY(depth == 0)) {
30751 return;
30752 }
30753
30754 /* To handle deeper indents efficiently, make use of copies we've
30755 * already emitted. In effect we can emit a sequence of 1, 2, 4,
30756 * 8, etc copies, and then finish the last run. Byte counters
30757 * avoid multiply with gap_len on every loop.
30758 */
30759
30760 gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap);
30761 gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap);
30762 DUK_ASSERT(gap_len > 0);
30763
30764 need_bytes = gap_len * depth;
30765 p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
30766 p_start = p;
30767
30768 DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len);
30769 p += gap_len;
30770 avail_bytes = gap_len;
30771 DUK_ASSERT(need_bytes >= gap_len);
30772 need_bytes -= gap_len;
30773
30774 while (need_bytes >= avail_bytes) {
30775 DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes);
30776 p += avail_bytes;
30777 need_bytes -= avail_bytes;
30778 avail_bytes <<= 1;
30779 }
30780
30781 DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */
30782 DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes);
30783 p += need_bytes;
30784 /*avail_bytes += need_bytes*/
30785
30786 DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p);
30787}
30788#endif /* DUK_USE_PREFER_SIZE */
30789
30790/* Shared entry handling for object/array serialization. */
30791DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
30792 duk_context *ctx = (duk_context *) js_ctx->thr;
30793 duk_hobject *h_target;
30794 duk_uint_fast32_t i, n;
30795
30796 *entry_top = duk_get_top(ctx);
30797
30798 duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
30799
30800 /* Loop check using a hybrid approach: a fixed-size visited[] array
30801 * with overflow in a loop check object.
30802 */
30803
30804 h_target = duk_get_hobject(ctx, -1); /* object or array */
30805 DUK_ASSERT(h_target != NULL);
30806
30807 n = js_ctx->recursion_depth;
30808 if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
30809 n = DUK_JSON_ENC_LOOPARRAY;
30810 }
30811 for (i = 0; i < n; i++) {
30812 if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
30813 DUK_DD(DUK_DDPRINT("slow path loop detect"));
30814 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
30815 }
30816 }
30817 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
30818 js_ctx->visiting[js_ctx->recursion_depth] = h_target;
30819 } else {
30820 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
30821 duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
30822 if (duk_has_prop(ctx, js_ctx->idx_loop)) {
30823 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
30824 }
30825 duk_push_true(ctx); /* -> [ ... voidp true ] */
30826 duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
30827 }
30828
30829 /* C recursion check. */
30830
30831 DUK_ASSERT(js_ctx->recursion_depth >= 0);
30832 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
30833 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
30834 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT);
30835 }
30836 js_ctx->recursion_depth++;
30837
30838 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
30839 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
30840}
30841
30842/* Shared exit handling for object/array serialization. */
30843DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
30844 duk_context *ctx = (duk_context *) js_ctx->thr;
30845 duk_hobject *h_target;
30846
30847 /* C recursion check. */
30848
30849 DUK_ASSERT(js_ctx->recursion_depth > 0);
30850 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
30851 js_ctx->recursion_depth--;
30852
30853 /* Loop check. */
30854
30855 h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
30856 DUK_ASSERT(h_target != NULL);
30857
30858 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
30859 /* Previous entry was inside visited[], nothing to do. */
30860 } else {
30861 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
30862 duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
30863 }
30864
30865 /* Restore stack top after unbalanced code paths. */
30866 duk_set_top(ctx, *entry_top);
30867
30868 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
30869 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
30870}
30871
30872/* The JO(value) operation: encode object.
30873 *
30874 * Stack policy: [ object ] -> [ object ].
30875 */
30876DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
30877 duk_context *ctx = (duk_context *) js_ctx->thr;
30878 duk_hstring *h_key;
30879 duk_idx_t entry_top;
30880 duk_idx_t idx_obj;
30881 duk_idx_t idx_keys;
30882 duk_bool_t emitted;
30883 duk_uarridx_t arr_len, i;
30884 duk_size_t prev_size;
30885
30886 DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
30887
30888 duk__enc_objarr_entry(js_ctx, &entry_top);
30889
30890 idx_obj = entry_top - 1;
30891
30892 if (js_ctx->idx_proplist >= 0) {
30893 idx_keys = js_ctx->idx_proplist;
30894 } else {
30895 /* XXX: would be nice to enumerate an object at specified index */
30896 duk_dup(ctx, idx_obj);
30897 (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
30898 idx_keys = duk_require_normalize_index(ctx, -1);
30899 /* leave stack unbalanced on purpose */
30900 }
30901
30902 DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
30903 (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys)));
30904
30905 /* Steps 8-10 have been merged to avoid a "partial" variable. */
30906
30907 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
30908
30909 /* XXX: keys is an internal object with all keys to be processed
30910 * in its (gapless) array part. Because nobody can touch the keys
30911 * object, we could iterate its array part directly (keeping in mind
30912 * that it can be reallocated).
30913 */
30914
30915 arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys);
30916 emitted = 0;
30917 for (i = 0; i < arr_len; i++) {
30918 duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */
30919
30920 DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
30921 (duk_tval *) duk_get_tval(ctx, idx_obj),
30922 (duk_tval *) duk_get_tval(ctx, -1)));
30923
30924 h_key = duk_get_hstring(ctx, -1);
30925 DUK_ASSERT(h_key != NULL);
30926
30927 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
30928 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
30929 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
30930 duk__enc_key_autoquote(js_ctx, h_key);
30931 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
30932 } else {
30933 duk__enc_key_autoquote(js_ctx, h_key);
30934 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
30935 }
30936
30937 /* [ ... key ] */
30938
30939 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) {
30940 /* Value would yield 'undefined', so skip key altogether.
30941 * Side effects have already happened.
30942 */
30943 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
30944 } else {
30945 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
30946 emitted = 1;
30947 }
30948
30949 /* [ ... ] */
30950 }
30951
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);
30958 }
30959 }
30960 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
30961
30962 duk__enc_objarr_exit(js_ctx, &entry_top);
30963
30964 DUK_ASSERT_TOP(ctx, entry_top);
30965}
30966
30967/* The JA(value) operation: encode array.
30968 *
30969 * Stack policy: [ array ] -> [ array ].
30970 */
30971DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
30972 duk_context *ctx = (duk_context *) js_ctx->thr;
30973 duk_idx_t entry_top;
30974 duk_idx_t idx_arr;
30975 duk_bool_t emitted;
30976 duk_uarridx_t i, arr_len;
30977
30978 DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
30979 (duk_tval *) duk_get_tval(ctx, -1)));
30980
30981 duk__enc_objarr_entry(js_ctx, &entry_top);
30982
30983 idx_arr = entry_top - 1;
30984
30985 /* Steps 8-10 have been merged to avoid a "partial" variable. */
30986
30987 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
30988
30989 arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
30990 emitted = 0;
30991 for (i = 0; i < arr_len; i++) {
30992 DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
30993 (duk_tval *) duk_get_tval(ctx, idx_arr),
30994 (long) i, (long) arr_len));
30995
30996 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
30997 DUK_ASSERT(js_ctx->recursion_depth >= 1);
30998 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
30999 }
31000
31001 /* XXX: duk_push_uint_string() */
31002 duk_push_uint(ctx, (duk_uint_t) i);
31003 duk_to_string(ctx, -1); /* -> [ ... key ] */
31004
31005 /* [ ... key ] */
31006
31007 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) {
31008 /* Value would normally be omitted, replace with 'null'. */
31009 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31010 } else {
31011 ;
31012 }
31013
31014 /* [ ... ] */
31015
31016 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
31017 emitted = 1;
31018 }
31019
31020 if (emitted) {
31021 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
31022 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
31023 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31024 DUK_ASSERT(js_ctx->recursion_depth >= 1);
31025 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
31026 }
31027 }
31028 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
31029
31030 duk__enc_objarr_exit(js_ctx, &entry_top);
31031
31032 DUK_ASSERT_TOP(ctx, entry_top);
31033}
31034
31035/* The Str(key, holder) operation.
31036 *
31037 * Stack policy: [ ... key ] -> [ ... ]
31038 */
31039DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
31040 duk_context *ctx = (duk_context *) js_ctx->thr;
31041 duk_hthread *thr = (duk_hthread *) ctx;
31042 duk_hobject *h_tmp;
31043 duk_tval *tv;
31044 duk_tval *tv_holder;
31045 duk_tval *tv_key;
31046 duk_small_int_t c;
31047
31048 DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
31049 (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder),
31050 (duk_tval *) duk_get_tval(ctx, -1)));
31051
31052 DUK_UNREF(thr);
31053
31054 tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder);
31055 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
31056 tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
31057 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
31058 (void) duk_hobject_getprop(thr, tv_holder, tv_key);
31059
31060 /* -> [ ... key val ] */
31061
31062 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
31063
31064 h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1);
31065 if (h_tmp != NULL) {
31066 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON);
31067 h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); /* toJSON() can also be a lightfunc */
31068
31069 if (h_tmp != NULL && DUK_HOBJECT_IS_CALLABLE(h_tmp)) {
31070 DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
31071 /* XXX: duk_dup_unvalidated(ctx, -2) etc. */
31072 duk_dup(ctx, -2); /* -> [ ... key val toJSON val ] */
31073 duk_dup(ctx, -4); /* -> [ ... key val toJSON val key ] */
31074 duk_call_method(ctx, 1); /* -> [ ... key val val' ] */
31075 duk_remove(ctx, -2); /* -> [ ... key val' ] */
31076 } else {
31077 duk_pop(ctx); /* -> [ ... key val ] */
31078 }
31079 }
31080
31081 /* [ ... key val ] */
31082
31083 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
31084
31085 if (js_ctx->h_replacer) {
31086 /* XXX: Here a "slice copy" would be useful. */
31087 DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
31088 duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
31089 duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */
31090 duk_dup(ctx, -4); /* -> [ ... key val replacer holder key ] */
31091 duk_dup(ctx, -4); /* -> [ ... key val replacer holder key val ] */
31092 duk_call_method(ctx, 2); /* -> [ ... key val val' ] */
31093 duk_remove(ctx, -2); /* -> [ ... key val' ] */
31094 }
31095
31096 /* [ ... key val ] */
31097
31098 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
31099
31100 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
31101 if (DUK_TVAL_IS_OBJECT(tv)) {
31102 duk_hobject *h;
31103
31104 h = DUK_TVAL_GET_OBJECT(tv);
31105 DUK_ASSERT(h != NULL);
31106
31107 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
31108#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31109 duk_hbufferobject *h_bufobj;
31110 h_bufobj = (duk_hbufferobject *) h;
31111 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
31112
31113 /* Conceptually we'd extract the plain underlying buffer
31114 * or its slice and then do a type mask check below to
31115 * see if we should reject it. Do the mask check here
31116 * instead to avoid making a copy of the buffer slice.
31117 */
31118
31119 if (js_ctx->mask_for_undefined & DUK_TYPE_MASK_BUFFER) {
31120 DUK_DDD(DUK_DDDPRINT("-> bufferobject (-> plain buffer) will result in undefined (type mask check)"));
31121 goto pop2_undef;
31122 }
31123 DUK_DDD(DUK_DDDPRINT("-> bufferobject won't result in undefined, encode directly"));
31124 duk__enc_bufferobject(js_ctx, h_bufobj);
31125 goto pop2_emitted;
31126#else
31127 DUK_DDD(DUK_DDDPRINT("no JX/JC support, bufferobject/buffer will always result in undefined"));
31128 goto pop2_undef;
31129#endif
31130 } else {
31131 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
31132 switch ((int) c) {
31133 case DUK_HOBJECT_CLASS_NUMBER: {
31134 DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
31135 duk_to_number(ctx, -1);
31136 /* The coercion potentially invokes user .valueOf() and .toString()
31137 * but can't result in a function value because [[DefaultValue]] would
31138 * reject such a result: test-dev-json-stringify-coercion-1.js.
31139 */
31140 DUK_ASSERT(!duk_is_callable(ctx, -1));
31141 break;
31142 }
31143 case DUK_HOBJECT_CLASS_STRING: {
31144 DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
31145 duk_to_string(ctx, -1);
31146 /* Same coercion behavior as for Number. */
31147 DUK_ASSERT(!duk_is_callable(ctx, -1));
31148 break;
31149 }
31150#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31151 case DUK_HOBJECT_CLASS_POINTER:
31152#endif
31153 case DUK_HOBJECT_CLASS_BOOLEAN: {
31154 DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
31155 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
31156 duk_remove(ctx, -2);
31157 break;
31158 }
31159 default: {
31160 /* Normal object which doesn't get automatically coerced to a
31161 * primitive value. Functions are checked for specially. The
31162 * primitive value coercions for Number, String, Pointer, and
31163 * Boolean can't result in functions so suffices to check here.
31164 */
31165 DUK_ASSERT(h != NULL);
31166 if (DUK_HOBJECT_IS_CALLABLE(h)) {
31167#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31168 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
31169 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
31170 /* We only get here when doing non-standard JSON encoding */
31171 DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
31172 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
31173 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
31174 goto pop2_emitted;
31175 } else {
31176 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
31177 goto pop2_undef;
31178 }
31179#else /* DUK_USE_JX || DUK_USE_JC */
31180 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
31181 goto pop2_undef;
31182#endif /* DUK_USE_JX || DUK_USE_JC */
31183 }
31184 }
31185 } /* end switch */
31186 }
31187 }
31188
31189 /* [ ... key val ] */
31190
31191 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
31192
31193 if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
31194 /* will result in undefined */
31195 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
31196 goto pop2_undef;
31197 }
31198 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
31199
31200 switch (DUK_TVAL_GET_TAG(tv)) {
31201#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31202 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
31203 case DUK_TAG_UNDEFINED: {
31204 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
31205 break;
31206 }
31207#endif
31208 case DUK_TAG_NULL: {
31209 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31210 break;
31211 }
31212 case DUK_TAG_BOOLEAN: {
31213 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
31214 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
31215 break;
31216 }
31217#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31218 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
31219 case DUK_TAG_POINTER: {
31220 duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
31221 break;
31222 }
31223#endif /* DUK_USE_JX || DUK_USE_JC */
31224 case DUK_TAG_STRING: {
31225 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
31226 DUK_ASSERT(h != NULL);
31227
31228 duk__enc_quote_string(js_ctx, h);
31229 break;
31230 }
31231 case DUK_TAG_OBJECT: {
31232 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
31233 DUK_ASSERT(h != NULL);
31234
31235 /* Function values are handled completely above (including
31236 * coercion results):
31237 */
31238 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h));
31239
31240 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
31241 duk__enc_array(js_ctx);
31242 } else {
31243 duk__enc_object(js_ctx);
31244 }
31245 break;
31246 }
31247#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31248 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
31249 case DUK_TAG_BUFFER: {
31250 duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
31251 break;
31252 }
31253#endif /* DUK_USE_JX || DUK_USE_JC */
31254 case DUK_TAG_LIGHTFUNC: {
31255#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31256 /* We only get here when doing non-standard JSON encoding */
31257 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
31258 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
31259#else
31260 /* Standard JSON omits functions */
31261 DUK_UNREACHABLE();
31262#endif
31263 break;
31264 }
31265#if defined(DUK_USE_FASTINT)
31266 case DUK_TAG_FASTINT:
31267 /* Number serialization has a significant impact relative to
31268 * other fast path code, so careful fast path for fastints.
31269 */
31270 duk__enc_fastint_tval(js_ctx, tv);
31271 break;
31272#endif
31273 default: {
31274 /* number */
31275 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
31276 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
31277 /* XXX: A fast path for usual integers would be useful when
31278 * fastint support is not enabled.
31279 */
31280 duk__enc_double(js_ctx);
31281 break;
31282 }
31283 }
31284
31285 pop2_emitted:
31286 duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
31287 return 1; /* emitted */
31288
31289 pop2_undef:
31290 duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
31291 return 0; /* not emitted */
31292}
31293
31294/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
31295DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
31296 duk_hobject *h;
31297 duk_small_int_t c;
31298
31299 DUK_ASSERT(tv != NULL);
31300 if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) {
31301 return 1;
31302 } else if (DUK_TVAL_IS_OBJECT(tv)) {
31303 h = DUK_TVAL_GET_OBJECT(tv);
31304 DUK_ASSERT(h != NULL);
31305 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
31306 if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) {
31307 return 1;
31308 }
31309 }
31310
31311 return 0;
31312}
31313
31314/*
31315 * JSON.stringify() fast path
31316 *
31317 * Otherwise supports full JSON, JX, and JC features, but bails out on any
31318 * possible side effect which might change the value being serialized. The
31319 * fast path can take advantage of the fact that the value being serialized
31320 * is unchanged so that we can walk directly through property tables etc.
31321 */
31322
31323#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
31324DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
31325 duk_uint_fast32_t i, n;
31326
31327 DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv));
31328
31329 DUK_ASSERT(js_ctx != NULL);
31330 DUK_ASSERT(js_ctx->thr != NULL);
31331
31332#if 0 /* disabled for now */
31333 restart_match:
31334#endif
31335
31336 DUK_ASSERT(tv != NULL);
31337
31338 switch (DUK_TVAL_GET_TAG(tv)) {
31339 case DUK_TAG_UNDEFINED: {
31340#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31341 if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) {
31342 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
31343 break;
31344 } else {
31345 goto emit_undefined;
31346 }
31347#else
31348 goto emit_undefined;
31349#endif
31350 }
31351 case DUK_TAG_NULL: {
31352 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31353 break;
31354 }
31355 case DUK_TAG_BOOLEAN: {
31356 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
31357 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
31358 break;
31359 }
31360 case DUK_TAG_STRING: {
31361 duk_hstring *h;
31362
31363 h = DUK_TVAL_GET_STRING(tv);
31364 DUK_ASSERT(h != NULL);
31365 duk__enc_quote_string(js_ctx, h);
31366 break;
31367 }
31368 case DUK_TAG_OBJECT: {
31369 duk_hobject *obj;
31370 duk_tval *tv_val;
31371 duk_bool_t emitted = 0;
31372 duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
31373 c_func, c_bufobj, c_object;
31374
31375 /* For objects JSON.stringify() only looks for own, enumerable
31376 * properties which is nice for the fast path here.
31377 *
31378 * For arrays JSON.stringify() uses [[Get]] so it will actually
31379 * inherit properties during serialization! This fast path
31380 * supports gappy arrays as long as there's no actual inherited
31381 * property (which might be a getter etc).
31382 *
31383 * Since recursion only happens for objects, we can have both
31384 * recursion and loop checks here. We use a simple, depth-limited
31385 * loop check in the fast path because the object-based tracking
31386 * is very slow (when tested, it accounted for 50% of fast path
31387 * execution time for input data with a lot of small objects!).
31388 */
31389
31390 /* XXX: for real world code, could just ignore array inheritance
31391 * and only look at array own properties.
31392 */
31393
31394 /* We rely on a few object flag / class number relationships here,
31395 * assert for them.
31396 */
31397
31398 obj = DUK_TVAL_GET_OBJECT(tv);
31399 DUK_ASSERT(obj != NULL);
31400 DUK_ASSERT_HOBJECT_VALID(obj);
31401
31402 /* Once recursion depth is increased, exit path must decrease
31403 * it (though it's OK to abort the fast path).
31404 */
31405
31406 DUK_ASSERT(js_ctx->recursion_depth >= 0);
31407 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31408 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
31409 DUK_DD(DUK_DDPRINT("fast path recursion limit"));
31410 DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT);
31411 }
31412
31413 for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
31414 if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
31415 DUK_DD(DUK_DDPRINT("fast path loop detect"));
31416 DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT);
31417 }
31418 }
31419
31420 /* Guaranteed by recursion_limit setup so we don't have to
31421 * check twice.
31422 */
31423 DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY);
31424 js_ctx->visiting[js_ctx->recursion_depth] = obj;
31425 js_ctx->recursion_depth++;
31426
31427 /* If object has a .toJSON() property, we can't be certain
31428 * that it wouldn't mutate any value arbitrarily, so bail
31429 * out of the fast path.
31430 *
31431 * If an object is a Proxy we also can't avoid side effects
31432 * so abandon.
31433 */
31434 /* XXX: non-callable .toJSON() doesn't need to cause an abort
31435 * but does at the moment, probably not worth fixing.
31436 */
31437 if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
31438 DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
31439 DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
31440 goto abort_fastpath;
31441 }
31442
31443 /* We could use a switch-case for the class number but it turns out
31444 * a small if-else ladder on class masks is better. The if-ladder
31445 * should be in order of relevancy.
31446 */
31447
31448 /* XXX: move masks to js_ctx? they don't change during one
31449 * fast path invocation.
31450 */
31451 DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31);
31452#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31453 if (js_ctx->flag_ext_custom_or_compatible) {
31454 c_all = DUK_HOBJECT_CMASK_ALL;
31455 c_array = DUK_HOBJECT_CMASK_ARRAY;
31456 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
31457 DUK_HOBJECT_CMASK_STRING |
31458 DUK_HOBJECT_CMASK_BOOLEAN |
31459 DUK_HOBJECT_CMASK_POINTER;
31460 c_func = DUK_HOBJECT_CMASK_FUNCTION;
31461 c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
31462 c_undef = 0;
31463 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
31464 }
31465 else
31466#endif
31467 {
31468 c_all = DUK_HOBJECT_CMASK_ALL;
31469 c_array = DUK_HOBJECT_CMASK_ARRAY;
31470 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
31471 DUK_HOBJECT_CMASK_STRING |
31472 DUK_HOBJECT_CMASK_BOOLEAN;
31473 c_func = 0;
31474 c_bufobj = 0;
31475 c_undef = DUK_HOBJECT_CMASK_FUNCTION |
31476 DUK_HOBJECT_CMASK_POINTER |
31477 DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
31478 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
31479 }
31480
31481 c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
31482 if (c_bit & c_object) {
31483 /* All other object types. */
31484 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
31485
31486 /* A non-Array object should not have an array part in practice.
31487 * But since it is supported internally (and perhaps used at some
31488 * point), check and abandon if that's the case.
31489 */
31490 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
31491 DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path"));
31492 goto abort_fastpath;
31493 }
31494
31495 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) {
31496 duk_hstring *k;
31497 duk_size_t prev_size;
31498
31499 k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i);
31500 if (!k) {
31501 continue;
31502 }
31503 if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
31504 continue;
31505 }
31506 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) {
31507 /* Getter might have arbitrary side effects,
31508 * so bail out.
31509 */
31510 DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
31511 goto abort_fastpath;
31512 }
31513 if (DUK_HSTRING_HAS_INTERNAL(k)) {
31514 continue;
31515 }
31516
31517 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i);
31518
31519 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
31520 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31521 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
31522 duk__enc_key_autoquote(js_ctx, k);
31523 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
31524 } else {
31525 duk__enc_key_autoquote(js_ctx, k);
31526 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
31527 }
31528
31529 if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
31530 DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon"));
31531 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
31532 } else {
31533 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
31534 emitted = 1;
31535 }
31536 }
31537
31538 /* If any non-Array value had enumerable virtual own
31539 * properties, they should be serialized here. Standard
31540 * types don't.
31541 */
31542
31543 if (emitted) {
31544 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
31545 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
31546 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31547 DUK_ASSERT(js_ctx->recursion_depth >= 1);
31548 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
31549 }
31550 }
31551 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
31552 } else if (c_bit & c_array) {
31553 duk_uint_fast32_t arr_len;
31554 duk_uint_fast32_t asize;
31555
31556 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
31557
31558 /* Assume arrays are dense in the fast path. */
31559 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
31560 DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path"));
31561 goto abort_fastpath;
31562 }
31563
31564 arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj);
31565 asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
31566 if (arr_len > asize) {
31567 /* Array length is larger than 'asize'. This shouldn't
31568 * happen in practice. Bail out just in case.
31569 */
31570 DUK_DD(DUK_DDPRINT("arr_len > asize, abort fast path"));
31571 goto abort_fastpath;
31572 }
31573 /* Array part may be larger than 'length'; if so, iterate
31574 * only up to array 'length'.
31575 */
31576 for (i = 0; i < arr_len; i++) {
31577 DUK_ASSERT(i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj));
31578
31579 tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
31580
31581 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31582 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
31583 }
31584
31585 if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) {
31586 /* Gap in array; check for inherited property,
31587 * bail out if one exists. This should be enough
31588 * to support gappy arrays for all practical code.
31589 */
31590 duk_hstring *h_tmp;
31591 duk_bool_t has_inherited;
31592
31593 /* XXX: refactor into an internal helper, pretty awkward */
31594 duk_push_uint((duk_context *) js_ctx->thr, (duk_uint_t) i);
31595 h_tmp = duk_to_hstring((duk_context *) js_ctx->thr, -1);
31596 DUK_ASSERT(h_tmp != NULL);
31597 has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
31598 duk_pop((duk_context *) js_ctx->thr);
31599
31600 if (has_inherited) {
31601 DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
31602 goto abort_fastpath;
31603 }
31604
31605 /* Ordinary gap, undefined encodes to 'null' in
31606 * standard JSON (and no JX/JC support here now).
31607 */
31608 DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
31609#if defined(DUK_USE_JX)
31610 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
31611#else
31612 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31613#endif
31614 } else {
31615 if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
31616 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31617 }
31618 }
31619
31620 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
31621 emitted = 1;
31622 }
31623
31624 if (emitted) {
31625 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
31626 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
31627 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31628 DUK_ASSERT(js_ctx->recursion_depth >= 1);
31629 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
31630 }
31631 }
31632 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
31633 } else if (c_bit & c_unbox) {
31634 /* Certain boxed types are required to go through
31635 * automatic unboxing. Rely on internal value being
31636 * sane (to avoid infinite recursion).
31637 */
31638#if 1
31639 /* The code below is incorrect if .toString() or .valueOf() have
31640 * have been overridden. The correct approach would be to look up
31641 * the method(s) and if they resolve to the built-in function we
31642 * can safely bypass it and look up the internal value directly.
31643 * Unimplemented for now, abort fast path for boxed values.
31644 */
31645 goto abort_fastpath;
31646#else /* disabled */
31647 /* Disabled until fixed, see above. */
31648 duk_tval *tv_internal;
31649
31650 DUK_DD(DUK_DDPRINT("auto unboxing in fast path"));
31651
31652 tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj);
31653 DUK_ASSERT(tv_internal != NULL);
31654 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) ||
31655 DUK_TVAL_IS_NUMBER(tv_internal) ||
31656 DUK_TVAL_IS_BOOLEAN(tv_internal) ||
31657 DUK_TVAL_IS_POINTER(tv_internal));
31658
31659 tv = tv_internal;
31660 DUK_ASSERT(js_ctx->recursion_depth > 0);
31661 js_ctx->recursion_depth--; /* required to keep recursion depth correct */
31662 goto restart_match;
31663#endif /* disabled */
31664#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31665 } else if (c_bit & c_func) {
31666 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
31667 } else if (c_bit & c_bufobj) {
31668 duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj);
31669#endif
31670 } else {
31671 DUK_ASSERT((c_bit & c_undef) != 0);
31672
31673 /* Must decrease recursion depth before returning. */
31674 DUK_ASSERT(js_ctx->recursion_depth > 0);
31675 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31676 js_ctx->recursion_depth--;
31677 goto emit_undefined;
31678 }
31679
31680 DUK_ASSERT(js_ctx->recursion_depth > 0);
31681 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31682 js_ctx->recursion_depth--;
31683 break;
31684 }
31685 case DUK_TAG_BUFFER: {
31686#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31687 if (js_ctx->flag_ext_custom_or_compatible) {
31688 duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
31689 break;
31690 } else {
31691 goto emit_undefined;
31692 }
31693#else
31694 goto emit_undefined;
31695#endif
31696 }
31697 case DUK_TAG_POINTER: {
31698#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31699 if (js_ctx->flag_ext_custom_or_compatible) {
31700 duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
31701 break;
31702 } else {
31703 goto emit_undefined;
31704 }
31705#else
31706 goto emit_undefined;
31707#endif
31708 }
31709 case DUK_TAG_LIGHTFUNC: {
31710 /* A lightfunc might also inherit a .toJSON() so just bail out. */
31711 /* XXX: Could just lookup .toJSON() and continue in fast path,
31712 * as it would almost never be defined.
31713 */
31714 DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path"));
31715 goto abort_fastpath;
31716 }
31717#if defined(DUK_USE_FASTINT)
31718 case DUK_TAG_FASTINT: {
31719 /* Number serialization has a significant impact relative to
31720 * other fast path code, so careful fast path for fastints.
31721 */
31722 duk__enc_fastint_tval(js_ctx, tv);
31723 break;
31724 }
31725#endif
31726 default: {
31727 /* XXX: A fast path for usual integers would be useful when
31728 * fastint support is not enabled.
31729 */
31730 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
31731 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
31732
31733 /* XXX: Stack discipline is annoying, could be changed in numconv. */
31734 duk_push_tval((duk_context *) js_ctx->thr, tv);
31735 duk__enc_double(js_ctx);
31736 duk_pop((duk_context *) js_ctx->thr);
31737
31738#if 0
31739 /* Could also rely on native sprintf(), but it will handle
31740 * values like NaN, Infinity, -0, exponent notation etc in
31741 * a JSON-incompatible way.
31742 */
31743 duk_double_t d;
31744 char buf[64];
31745
31746 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
31747 d = DUK_TVAL_GET_DOUBLE(tv);
31748 DUK_SPRINTF(buf, "%lg", d);
31749 DUK__EMIT_CSTR(js_ctx, buf);
31750#endif
31751 }
31752 }
31753 return 1; /* not undefined */
31754
31755 emit_undefined:
31756 return 0; /* value was undefined/unsupported */
31757
31758 abort_fastpath:
31759 /* Error message doesn't matter: the error is ignored anyway. */
31760 DUK_DD(DUK_DDPRINT("aborting fast path"));
31761 DUK_ERROR_INTERNAL_DEFMSG(js_ctx->thr);
31762 return 0; /* unreachable */
31763}
31764
31765DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) {
31766 duk_json_enc_ctx *js_ctx;
31767 duk_tval *tv;
31768
31769 DUK_ASSERT(ctx != NULL);
31770 tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
31771 DUK_ASSERT(DUK_TVAL_IS_POINTER(tv));
31772 js_ctx = (duk_json_enc_ctx *) DUK_TVAL_GET_POINTER(tv);
31773 DUK_ASSERT(js_ctx != NULL);
31774
31775 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
31776 if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
31777 DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
31778 return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */
31779 }
31780
31781 return 0;
31782}
31783#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
31784
31785/*
31786 * Top level wrappers
31787 */
31788
31789DUK_INTERNAL
31790void duk_bi_json_parse_helper(duk_context *ctx,
31791 duk_idx_t idx_value,
31792 duk_idx_t idx_reviver,
31793 duk_small_uint_t flags) {
31794 duk_hthread *thr = (duk_hthread *) ctx;
31795 duk_json_dec_ctx js_ctx_alloc;
31796 duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
31797 duk_hstring *h_text;
31798#ifdef DUK_USE_ASSERTIONS
31799 duk_idx_t entry_top = duk_get_top(ctx);
31800#endif
31801
31802 /* negative top-relative indices not allowed now */
31803 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
31804 DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
31805
31806 DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
31807 (duk_tval *) duk_get_tval(ctx, idx_value),
31808 (duk_tval *) duk_get_tval(ctx, idx_reviver),
31809 (unsigned long) flags,
31810 (long) duk_get_top(ctx)));
31811
31812 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
31813 js_ctx->thr = thr;
31814#ifdef DUK_USE_EXPLICIT_NULL_INIT
31815 /* nothing now */
31816#endif
31817 js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
31818 DUK_ASSERT(js_ctx->recursion_depth == 0);
31819
31820 /* Flag handling currently assumes that flags are consistent. This is OK
31821 * because the call sites are now strictly controlled.
31822 */
31823
31824 js_ctx->flags = flags;
31825#if defined(DUK_USE_JX)
31826 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
31827#endif
31828#if defined(DUK_USE_JC)
31829 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
31830#endif
31831#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31832 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
31833#endif
31834
31835 h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */
31836 DUK_ASSERT(h_text != NULL);
31837
31838 /* JSON parsing code is allowed to read [p_start,p_end]: p_end is
31839 * valid and points to the string NUL terminator (which is always
31840 * guaranteed for duk_hstrings.
31841 */
31842 js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
31843 js_ctx->p = js_ctx->p_start;
31844 js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
31845 DUK_HSTRING_GET_BYTELEN(h_text);
31846 DUK_ASSERT(*(js_ctx->p_end) == 0x00);
31847
31848 duk__dec_value(js_ctx); /* -> [ ... value ] */
31849
31850 /* Trailing whitespace has been eaten by duk__dec_value(), so if
31851 * we're not at end of input here, it's a SyntaxError.
31852 */
31853
31854 if (js_ctx->p != js_ctx->p_end) {
31855 duk__dec_syntax_error(js_ctx);
31856 }
31857
31858 if (duk_is_callable(ctx, idx_reviver)) {
31859 DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
31860 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
31861
31862 js_ctx->idx_reviver = idx_reviver;
31863
31864 duk_push_object(ctx);
31865 duk_dup(ctx, -2); /* -> [ ... val root val ] */
31866 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
31867 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
31868
31869 DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
31870 (duk_tval *) duk_get_tval(ctx, -2),
31871 (duk_tval *) duk_get_tval(ctx, -1)));
31872
31873 duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
31874 duk_remove(ctx, -2); /* -> [ ... val' ] */
31875 } else {
31876 DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
31877 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
31878 }
31879
31880 /* Final result is at stack top. */
31881
31882 DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
31883 (duk_tval *) duk_get_tval(ctx, idx_value),
31884 (duk_tval *) duk_get_tval(ctx, idx_reviver),
31885 (unsigned long) flags,
31886 (duk_tval *) duk_get_tval(ctx, -1),
31887 (long) duk_get_top(ctx)));
31888
31889 DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
31890}
31891
31892DUK_INTERNAL
31893void duk_bi_json_stringify_helper(duk_context *ctx,
31894 duk_idx_t idx_value,
31895 duk_idx_t idx_replacer,
31896 duk_idx_t idx_space,
31897 duk_small_uint_t flags) {
31898 duk_hthread *thr = (duk_hthread *) ctx;
31899 duk_json_enc_ctx js_ctx_alloc;
31900 duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
31901 duk_hobject *h;
31902 duk_idx_t idx_holder;
31903 duk_idx_t entry_top;
31904
31905 /* negative top-relative indices not allowed now */
31906 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
31907 DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0);
31908 DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
31909
31910 DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
31911 (duk_tval *) duk_get_tval(ctx, idx_value),
31912 (duk_tval *) duk_get_tval(ctx, idx_replacer),
31913 (duk_tval *) duk_get_tval(ctx, idx_space),
31914 (unsigned long) flags,
31915 (long) duk_get_top(ctx)));
31916
31917 entry_top = duk_get_top(ctx);
31918
31919 /*
31920 * Context init
31921 */
31922
31923 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
31924 js_ctx->thr = thr;
31925#ifdef DUK_USE_EXPLICIT_NULL_INIT
31926 js_ctx->h_replacer = NULL;
31927 js_ctx->h_gap = NULL;
31928#endif
31929 js_ctx->idx_proplist = -1;
31930
31931 /* Flag handling currently assumes that flags are consistent. This is OK
31932 * because the call sites are now strictly controlled.
31933 */
31934
31935 js_ctx->flags = flags;
31936 js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
31937 js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
31938#ifdef DUK_USE_JX
31939 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
31940#endif
31941#ifdef DUK_USE_JC
31942 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
31943#endif
31944#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31945 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
31946#endif
31947
31948 /* The #ifdef clutter here handles the JX/JC enable/disable
31949 * combinations properly.
31950 */
31951#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31952 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */
31953#if defined(DUK_USE_JX)
31954 if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
31955 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
31956 js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
31957 js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
31958 js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
31959 js_ctx->stridx_custom_function =
31960 (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
31961 DUK_STRIDX_JSON_EXT_FUNCTION2 :
31962 DUK_STRIDX_JSON_EXT_FUNCTION1;
31963 }
31964#endif /* DUK_USE_JX */
31965#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
31966 else
31967#endif /* DUK_USE_JX && DUK_USE_JC */
31968#if defined(DUK_USE_JC)
31969 if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
31970 js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
31971 js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
31972 js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
31973 js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
31974 js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
31975 }
31976#endif /* DUK_USE_JC */
31977#endif /* DUK_USE_JX || DUK_USE_JC */
31978
31979#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31980 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
31981 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
31982 DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */
31983 }
31984 else
31985#endif /* DUK_USE_JX || DUK_USE_JC */
31986 {
31987 js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
31988 DUK_TYPE_MASK_POINTER |
31989 DUK_TYPE_MASK_BUFFER |
31990 DUK_TYPE_MASK_LIGHTFUNC;
31991 }
31992
31993 DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
31994
31995 js_ctx->idx_loop = duk_push_object_internal(ctx);
31996 DUK_ASSERT(js_ctx->idx_loop >= 0);
31997
31998 /* [ ... buf loop ] */
31999
32000 /*
32001 * Process replacer/proplist (2nd argument to JSON.stringify)
32002 */
32003
32004 h = duk_get_hobject(ctx, idx_replacer);
32005 if (h != NULL) {
32006 if (DUK_HOBJECT_IS_CALLABLE(h)) {
32007 js_ctx->h_replacer = h;
32008 } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
32009 /* Here the specification requires correct array index enumeration
32010 * which is a bit tricky for sparse arrays (it is handled by the
32011 * enum setup code). We now enumerate ancestors too, although the
32012 * specification is not very clear on whether that is required.
32013 */
32014
32015 duk_uarridx_t plist_idx = 0;
32016 duk_small_uint_t enum_flags;
32017
32018 js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
32019
32020 enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
32021 DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
32022 duk_enum(ctx, idx_replacer, enum_flags);
32023 while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
32024 /* [ ... proplist enum_obj key val ] */
32025 if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
32026 /* XXX: duplicates should be eliminated here */
32027 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
32028 (duk_tval *) duk_get_tval(ctx, -2),
32029 (duk_tval *) duk_get_tval(ctx, -1)));
32030 duk_to_string(ctx, -1); /* extra coercion of strings is OK */
32031 duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
32032 plist_idx++;
32033 duk_pop(ctx);
32034 } else {
32035 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
32036 (duk_tval *) duk_get_tval(ctx, -2),
32037 (duk_tval *) duk_get_tval(ctx, -1)));
32038 duk_pop_2(ctx);
32039 }
32040 }
32041 duk_pop(ctx); /* pop enum */
32042
32043 /* [ ... proplist ] */
32044 }
32045 }
32046
32047 /* [ ... buf loop (proplist) ] */
32048
32049 /*
32050 * Process space (3rd argument to JSON.stringify)
32051 */
32052
32053 h = duk_get_hobject(ctx, idx_space);
32054 if (h != NULL) {
32055 int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
32056 if (c == DUK_HOBJECT_CLASS_NUMBER) {
32057 duk_to_number(ctx, idx_space);
32058 } else if (c == DUK_HOBJECT_CLASS_STRING) {
32059 duk_to_string(ctx, idx_space);
32060 }
32061 }
32062
32063 if (duk_is_number(ctx, idx_space)) {
32064 duk_small_int_t nspace;
32065 /* spaces[] must be static to allow initializer with old compilers like BCC */
32066 static const char spaces[10] = {
32067 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
32068 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
32069 DUK_ASC_SPACE, DUK_ASC_SPACE
32070 }; /* XXX: helper */
32071
32072 /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
32073 nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
32074 DUK_ASSERT(nspace >= 0 && nspace <= 10);
32075
32076 duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
32077 js_ctx->h_gap = duk_get_hstring(ctx, -1);
32078 DUK_ASSERT(js_ctx->h_gap != NULL);
32079 } else if (duk_is_string(ctx, idx_space)) {
32080 /* XXX: substring in-place at idx_place? */
32081 duk_dup(ctx, idx_space);
32082 duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
32083 js_ctx->h_gap = duk_get_hstring(ctx, -1);
32084 DUK_ASSERT(js_ctx->h_gap != NULL);
32085 } else {
32086 /* nop */
32087 }
32088
32089 if (js_ctx->h_gap != NULL) {
32090 /* if gap is empty, behave as if not given at all */
32091 if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
32092 js_ctx->h_gap = NULL;
32093 }
32094 }
32095
32096 /* [ ... buf loop (proplist) (gap) ] */
32097
32098 /*
32099 * Fast path: assume no mutation, iterate object property tables
32100 * directly; bail out if that assumption doesn't hold.
32101 */
32102
32103#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
32104 if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
32105 js_ctx->idx_proplist == -1) { /* proplist is very rare */
32106 duk_int_t pcall_rc;
32107#ifdef DUK_USE_MARK_AND_SWEEP
32108 duk_small_uint_t prev_mark_and_sweep_base_flags;
32109#endif
32110
32111 DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
32112
32113 /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[]
32114 * array so we don't need two counter checks in the fast path. The
32115 * slow path has a much larger recursion limit which we'll use if
32116 * necessary.
32117 */
32118 DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY);
32119 js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY;
32120 DUK_ASSERT(js_ctx->recursion_depth == 0);
32121
32122 /* Execute the fast path in a protected call. If any error is thrown,
32123 * fall back to the slow path. This includes e.g. recursion limit
32124 * because the fast path has a smaller recursion limit (and simpler,
32125 * limited loop detection).
32126 */
32127
32128 duk_push_pointer(ctx, (void *) js_ctx);
32129 duk_dup(ctx, idx_value);
32130
32131#if defined(DUK_USE_MARK_AND_SWEEP)
32132 /* Must prevent finalizers which may have arbitrary side effects. */
32133 prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
32134 thr->heap->mark_and_sweep_base_flags |=
32135 DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
32136 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */
32137#endif
32138
32139 pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/);
32140
32141#if defined(DUK_USE_MARK_AND_SWEEP)
32142 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
32143#endif
32144 if (pcall_rc == DUK_EXEC_SUCCESS) {
32145 DUK_DD(DUK_DDPRINT("fast path successful"));
32146 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
32147 goto replace_finished;
32148 }
32149
32150 /* We come here for actual aborts (like encountering .toJSON())
32151 * but also for recursion/loop errors. Bufwriter size can be
32152 * kept because we'll probably need at least as much as we've
32153 * allocated so far.
32154 */
32155 DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
32156 DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
32157 js_ctx->recursion_depth = 0;
32158 }
32159#endif
32160
32161 /*
32162 * Create wrapper object and serialize
32163 */
32164
32165 idx_holder = duk_push_object(ctx);
32166 duk_dup(ctx, idx_value);
32167 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
32168
32169 DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
32170 "proplist=%!T, gap=%!O, holder=%!T",
32171 (unsigned long) js_ctx->flags,
32172 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
32173 (duk_heaphdr *) js_ctx->h_replacer,
32174 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
32175 (duk_heaphdr *) js_ctx->h_gap,
32176 (duk_tval *) duk_get_tval(ctx, -1)));
32177
32178 /* serialize the wrapper with empty string key */
32179
32180 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
32181
32182 /* [ ... buf loop (proplist) (gap) holder "" ] */
32183
32184 js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
32185 DUK_ASSERT(js_ctx->recursion_depth == 0);
32186
32187 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
32188 /* Result is undefined. */
32189 duk_push_undefined(ctx);
32190 } else {
32191 /* Convert buffer to result string. */
32192 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
32193 }
32194
32195 DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
32196 "proplist=%!T, gap=%!O, holder=%!T",
32197 (unsigned long) js_ctx->flags,
32198 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
32199 (duk_heaphdr *) js_ctx->h_replacer,
32200 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
32201 (duk_heaphdr *) js_ctx->h_gap,
32202 (duk_tval *) duk_get_tval(ctx, idx_holder)));
32203
32204 /* The stack has a variable shape here, so force it to the
32205 * desired one explicitly.
32206 */
32207
32208#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
32209 replace_finished:
32210#endif
32211 duk_replace(ctx, entry_top);
32212 duk_set_top(ctx, entry_top + 1);
32213
32214 DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
32215 "flags=0x%08lx, result=%!T, stack_top=%ld",
32216 (duk_tval *) duk_get_tval(ctx, idx_value),
32217 (duk_tval *) duk_get_tval(ctx, idx_replacer),
32218 (duk_tval *) duk_get_tval(ctx, idx_space),
32219 (unsigned long) flags,
32220 (duk_tval *) duk_get_tval(ctx, -1),
32221 (long) duk_get_top(ctx)));
32222
32223 DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
32224}
32225
32226/*
32227 * Entry points
32228 */
32229
32230DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) {
32231 duk_bi_json_parse_helper(ctx,
32232 0 /*idx_value*/,
32233 1 /*idx_replacer*/,
32234 0 /*flags*/);
32235 return 1;
32236}
32237
32238DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
32239 duk_bi_json_stringify_helper(ctx,
32240 0 /*idx_value*/,
32241 1 /*idx_replacer*/,
32242 2 /*idx_space*/,
32243 0 /*flags*/);
32244 return 1;
32245}
32246
32247#undef DUK__JSON_DECSTR_BUFSIZE
32248#undef DUK__JSON_DECSTR_CHUNKSIZE
32249#undef DUK__JSON_ENCSTR_CHUNKSIZE
32250#undef DUK__JSON_STRINGIFY_BUFSIZE
32251#undef DUK__JSON_MAX_ESC_LEN
32252#line 1 "duk_bi_logger.c"
32253/*
32254 * Logging support
32255 */
32256
32257/* include removed: duk_internal.h */
32258
32259/* 3-letter log level strings */
32260DUK_LOCAL const duk_uint8_t duk__log_level_strings[] = {
32261 (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C,
32262 (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G,
32263 (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F,
32264 (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N,
32265 (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R,
32266 (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L
32267};
32268
32269/* Constructor */
32270DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) {
32271 duk_hthread *thr = (duk_hthread *) ctx;
32272 duk_idx_t nargs;
32273
32274 /* Calling as a non-constructor is not meaningful. */
32275 if (!duk_is_constructor_call(ctx)) {
32276 return DUK_RET_TYPE_ERROR;
32277 }
32278
32279 nargs = duk_get_top(ctx);
32280 duk_set_top(ctx, 1);
32281
32282 duk_push_this(ctx);
32283
32284 /* [ name this ] */
32285
32286 if (nargs == 0) {
32287 /* Automatic defaulting of logger name from caller. This would
32288 * work poorly with tail calls, but constructor calls are currently
32289 * never tail calls, so tail calls are not an issue now.
32290 */
32291
32292 if (thr->callstack_top >= 2) {
32293 duk_activation *act_caller = thr->callstack + thr->callstack_top - 2;
32294 duk_hobject *func_caller;
32295
32296 func_caller = DUK_ACT_GET_FUNC(act_caller);
32297 if (func_caller) {
32298 /* Stripping the filename might be a good idea
32299 * ("/foo/bar/quux.js" -> logger name "quux"),
32300 * but now used verbatim.
32301 */
32302 duk_push_hobject(ctx, func_caller);
32303 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
32304 duk_replace(ctx, 0);
32305 }
32306 }
32307 }
32308 /* the stack is unbalanced here on purpose; we only rely on the
32309 * initial two values: [ name this ].
32310 */
32311
32312 if (duk_is_string(ctx, 0)) {
32313 duk_dup(ctx, 0);
32314 duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N);
32315 } else {
32316 /* don't set 'n' at all, inherited value is used as name */
32317 }
32318
32319 duk_compact(ctx, 1);
32320
32321 return 0; /* keep default instance */
32322}
32323
32324/* Default function to format objects. Tries to use toLogString() but falls
32325 * back to toString(). Any errors are propagated out without catching.
32326 */
32327DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) {
32328 if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) {
32329 /* [ arg toLogString ] */
32330
32331 duk_dup(ctx, 0);
32332 duk_call_method(ctx, 0);
32333
32334 /* [ arg result ] */
32335 return 1;
32336 }
32337
32338 /* [ arg undefined ] */
32339 duk_pop(ctx);
32340 duk_to_string(ctx, 0);
32341 return 1;
32342}
32343
32344/* Default function to write a formatted log line. Writes to stderr,
32345 * appending a newline to the log line.
32346 *
32347 * The argument is a buffer whose visible size contains the log message.
32348 * This function should avoid coercing the buffer to a string to avoid
32349 * string table traffic.
32350 */
32351DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) {
32352 const char *data;
32353 duk_size_t data_len;
32354
32355 DUK_UNREF(ctx);
32356 DUK_UNREF(data);
32357 DUK_UNREF(data_len);
32358
32359#ifdef DUK_USE_FILE_IO
32360 data = (const char *) duk_require_buffer(ctx, 0, &data_len);
32361 DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR);
32362 DUK_FPUTC((int) '\n', DUK_STDERR);
32363 DUK_FFLUSH(DUK_STDERR);
32364#else
32365 /* nop */
32366#endif
32367 return 0;
32368}
32369
32370/* Log frontend shared helper, magic value indicates log level. Provides
32371 * frontend functions: trace(), debug(), info(), warn(), error(), fatal().
32372 * This needs to have small footprint, reasonable performance, minimal
32373 * memory churn, etc.
32374 */
32375DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
32376 duk_hthread *thr = (duk_hthread *) ctx;
32377 duk_double_t now;
32378 duk_small_int_t entry_lev = duk_get_current_magic(ctx);
32379 duk_small_int_t logger_lev;
32380 duk_int_t nargs;
32381 duk_int_t i;
32382 duk_size_t tot_len;
32383 const duk_uint8_t *arg_str;
32384 duk_size_t arg_len;
32385 duk_uint8_t *buf, *p;
32386 const duk_uint8_t *q;
32387 duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE];
32388 duk_size_t date_len;
32389 duk_small_int_t rc;
32390
32391 DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5);
32392 DUK_UNREF(thr);
32393
32394 /* XXX: sanitize to printable (and maybe ASCII) */
32395 /* XXX: better multiline */
32396
32397 /*
32398 * Logger arguments are:
32399 *
32400 * magic: log level (0-5)
32401 * this: logger
32402 * stack: plain log args
32403 *
32404 * We want to minimize memory churn so a two-pass approach
32405 * is used: first pass formats arguments and computes final
32406 * string length, second pass copies strings either into a
32407 * pre-allocated and reused buffer (short messages) or into a
32408 * newly allocated fixed buffer. If the backend function plays
32409 * nice, it won't coerce the buffer to a string (and thus
32410 * intern it).
32411 */
32412
32413 nargs = duk_get_top(ctx);
32414
32415 /* [ arg1 ... argN this ] */
32416
32417 /*
32418 * Log level check
32419 */
32420
32421 duk_push_this(ctx);
32422
32423 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L);
32424 logger_lev = (duk_small_int_t) duk_get_int(ctx, -1);
32425 if (entry_lev < logger_lev) {
32426 return 0;
32427 }
32428 /* log level could be popped but that's not necessary */
32429
32430 now = DUK_USE_DATE_GET_NOW(ctx);
32431 duk_bi_date_format_timeval(now, date_buf);
32432 date_len = DUK_STRLEN((const char *) date_buf);
32433
32434 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N);
32435 duk_to_string(ctx, -1);
32436 DUK_ASSERT(duk_is_string(ctx, -1));
32437
32438 /* [ arg1 ... argN this loggerLevel loggerName ] */
32439
32440 /*
32441 * Pass 1
32442 */
32443
32444 /* Line format: <time> <entryLev> <loggerName>: <msg> */
32445
32446 tot_len = 0;
32447 tot_len += 3 + /* separators: space, space, colon */
32448 3 + /* level string */
32449 date_len + /* time */
32450 duk_get_length(ctx, -1); /* loggerName */
32451
32452 for (i = 0; i < nargs; i++) {
32453 /* When formatting an argument to a string, errors may happen from multiple
32454 * causes. In general we want to catch obvious errors like a toLogString()
32455 * throwing an error, but we don't currently try to catch every possible
32456 * error. In particular, internal errors (like out of memory or stack) are
32457 * not caught. Also, we expect Error toString() to not throw an error.
32458 */
32459 if (duk_is_object(ctx, i)) {
32460 /* duk_pcall_prop() may itself throw an error, but we're content
32461 * in catching the obvious errors (like toLogString() throwing an
32462 * error).
32463 */
32464 duk_push_hstring_stridx(ctx, DUK_STRIDX_FMT);
32465 duk_dup(ctx, i);
32466 /* [ arg1 ... argN this loggerLevel loggerName 'fmt' arg ] */
32467 /* call: this.fmt(arg) */
32468 rc = duk_pcall_prop(ctx, -5 /*obj_index*/, 1 /*nargs*/);
32469 if (rc) {
32470 /* Keep the error as the result (coercing it might fail below,
32471 * but we don't catch that now).
32472 */
32473 ;
32474 }
32475 duk_replace(ctx, i);
32476 }
32477 (void) duk_to_lstring(ctx, i, &arg_len);
32478 tot_len++; /* sep (even before first one) */
32479 tot_len += arg_len;
32480 }
32481
32482 /*
32483 * Pass 2
32484 */
32485
32486 /* XXX: There used to be a shared log buffer here, but it was removed
32487 * when dynamic buffer spare was removed. The problem with using
32488 * bufwriter is that, without the spare, the buffer gets passed on
32489 * as an argument to the raw() call so it'd need to be resized
32490 * (reallocated) anyway. If raw() call convention is changed, this
32491 * could be made more efficient.
32492 */
32493
32494 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, tot_len);
32495 DUK_ASSERT(buf != NULL);
32496 p = buf;
32497
32498 DUK_MEMCPY((void *) p, (const void *) date_buf, (size_t) date_len);
32499 p += date_len;
32500 *p++ = (duk_uint8_t) DUK_ASC_SPACE;
32501
32502 q = duk__log_level_strings + (entry_lev * 3);
32503 DUK_MEMCPY((void *) p, (const void *) q, (size_t) 3);
32504 p += 3;
32505
32506 *p++ = (duk_uint8_t) DUK_ASC_SPACE;
32507
32508 arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len);
32509 DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
32510 p += arg_len;
32511
32512 *p++ = (duk_uint8_t) DUK_ASC_COLON;
32513
32514 for (i = 0; i < nargs; i++) {
32515 *p++ = (duk_uint8_t) DUK_ASC_SPACE;
32516
32517 arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len);
32518 DUK_ASSERT(arg_str != NULL);
32519 DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
32520 p += arg_len;
32521 }
32522 DUK_ASSERT(buf + tot_len == p);
32523
32524 /* [ arg1 ... argN this loggerLevel loggerName buffer ] */
32525
32526#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_LOGGING)
32527 /* Do debugger forwarding before raw() because the raw() function
32528 * doesn't get the log level right now.
32529 */
32530 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
32531 const char *log_buf;
32532 duk_size_t sz_buf;
32533 log_buf = (const char *) duk_get_buffer(ctx, -1, &sz_buf);
32534 DUK_ASSERT(log_buf != NULL);
32535 duk_debug_write_notify(thr, DUK_DBG_CMD_LOG);
32536 duk_debug_write_int(thr, (duk_int32_t) entry_lev);
32537 duk_debug_write_string(thr, (const char *) log_buf, sz_buf);
32538 duk_debug_write_eom(thr);
32539 }
32540#endif
32541
32542 /* Call this.raw(msg); look up through the instance allows user to override
32543 * the raw() function in the instance or in the prototype for maximum
32544 * flexibility.
32545 */
32546 duk_push_hstring_stridx(ctx, DUK_STRIDX_RAW);
32547 duk_dup(ctx, -2);
32548 /* [ arg1 ... argN this loggerLevel loggerName buffer 'raw' buffer ] */
32549 duk_call_prop(ctx, -6, 1); /* this.raw(buffer) */
32550
32551 return 0;
32552}
32553#line 1 "duk_bi_math.c"
32554/*
32555 * Math built-ins
32556 */
32557
32558/* include removed: duk_internal.h */
32559
32560#if defined(DUK_USE_MATH_BUILTIN)
32561
32562/*
32563 * Use static helpers which can work with math.h functions matching
32564 * the following signatures. This is not portable if any of these math
32565 * functions is actually a macro.
32566 *
32567 * Typing here is intentionally 'double' wherever values interact with
32568 * the standard library APIs.
32569 */
32570
32571typedef double (*duk__one_arg_func)(double);
32572typedef double (*duk__two_arg_func)(double, double);
32573
32574DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk__two_arg_func min_max) {
32575 duk_idx_t n = duk_get_top(ctx);
32576 duk_idx_t i;
32577 duk_double_t res = initial;
32578 duk_double_t t;
32579
32580 /*
32581 * Note: fmax() does not match the E5 semantics. E5 requires
32582 * that if -any- input to Math.max() is a NaN, the result is a
32583 * NaN. fmax() will return a NaN only if -both- inputs are NaN.
32584 * Same applies to fmin().
32585 *
32586 * Note: every input value must be coerced with ToNumber(), even
32587 * if we know the result will be a NaN anyway: ToNumber() may have
32588 * side effects for which even order of evaluation matters.
32589 */
32590
32591 for (i = 0; i < n; i++) {
32592 t = duk_to_number(ctx, i);
32593 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
32594 /* Note: not normalized, but duk_push_number() will normalize */
32595 res = (duk_double_t) DUK_DOUBLE_NAN;
32596 } else {
32597 res = (duk_double_t) min_max(res, (double) t);
32598 }
32599 }
32600
32601 duk_push_number(ctx, res);
32602 return 1;
32603}
32604
32605DUK_LOCAL double duk__fmin_fixed(double x, double y) {
32606 /* fmin() with args -0 and +0 is not guaranteed to return
32607 * -0 as Ecmascript requires.
32608 */
32609 if (x == 0 && y == 0) {
32610 /* XXX: what's the safest way of creating a negative zero? */
32611 if (DUK_SIGNBIT(x) != 0 || DUK_SIGNBIT(y) != 0) {
32612 return -0.0;
32613 } else {
32614 return +0.0;
32615 }
32616 }
32617#ifdef DUK_USE_MATH_FMIN
32618 return DUK_FMIN(x, y);
32619#else
32620 return (x < y ? x : y);
32621#endif
32622}
32623
32624DUK_LOCAL double duk__fmax_fixed(double x, double y) {
32625 /* fmax() with args -0 and +0 is not guaranteed to return
32626 * +0 as Ecmascript requires.
32627 */
32628 if (x == 0 && y == 0) {
32629 if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
32630 return +0.0;
32631 } else {
32632 return -0.0;
32633 }
32634 }
32635#ifdef DUK_USE_MATH_FMAX
32636 return DUK_FMAX(x, y);
32637#else
32638 return (x > y ? x : y);
32639#endif
32640}
32641
32642DUK_LOCAL double duk__round_fixed(double x) {
32643 /* Numbers half-way between integers must be rounded towards +Infinity,
32644 * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero
32645 * sign must be set appropriately. E5.1 Section 15.8.2.15.
32646 *
32647 * Note that ANSI C round() is "round to nearest integer, away from zero",
32648 * which is incorrect for negative values. Here we make do with floor().
32649 */
32650
32651 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
32652 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
32653 return x;
32654 }
32655
32656 /*
32657 * x is finite and non-zero
32658 *
32659 * -1.6 -> floor(-1.1) -> -2
32660 * -1.5 -> floor(-1.0) -> -1 (towards +Inf)
32661 * -1.4 -> floor(-0.9) -> -1
32662 * -0.5 -> -0.0 (special case)
32663 * -0.1 -> -0.0 (special case)
32664 * +0.1 -> +0.0 (special case)
32665 * +0.5 -> floor(+1.0) -> 1 (towards +Inf)
32666 * +1.4 -> floor(+1.9) -> 1
32667 * +1.5 -> floor(+2.0) -> 2 (towards +Inf)
32668 * +1.6 -> floor(+2.1) -> 2
32669 */
32670
32671 if (x >= -0.5 && x < 0.5) {
32672 /* +0.5 is handled by floor, this is on purpose */
32673 if (x < 0.0) {
32674 return -0.0;
32675 } else {
32676 return +0.0;
32677 }
32678 }
32679
32680 return DUK_FLOOR(x + 0.5);
32681}
32682
32683DUK_LOCAL double duk__pow_fixed(double x, double y) {
32684 /* The ANSI C pow() semantics differ from Ecmascript.
32685 *
32686 * E.g. when x==1 and y is +/- infinite, the Ecmascript required
32687 * result is NaN, while at least Linux pow() returns 1.
32688 */
32689
32690 duk_small_int_t cx, cy, sx;
32691
32692 DUK_UNREF(cx);
32693 DUK_UNREF(sx);
32694 cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
32695
32696 if (cy == DUK_FP_NAN) {
32697 goto ret_nan;
32698 }
32699 if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
32700 goto ret_nan;
32701 }
32702#if defined(DUK_USE_POW_NETBSD_WORKAROUND)
32703 /* See test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) does not
32704 * correctly handle some cases where x=+/-0. Specific fixes to these
32705 * here.
32706 */
32707 cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
32708 if (cx == DUK_FP_ZERO && y < 0.0) {
32709 sx = (duk_small_int_t) DUK_SIGNBIT(x);
32710 if (sx == 0) {
32711 /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
32712 * returns -Infinity instead when y is <0 and finite. The
32713 * if-clause also catches y == -Infinity (which works even
32714 * without the fix).
32715 */
32716 return DUK_DOUBLE_INFINITY;
32717 } else {
32718 /* Math.pow(-0,y) where y<0 should be:
32719 * - -Infinity if y<0 and an odd integer
32720 * - Infinity otherwise
32721 * NetBSD pow() returns -Infinity for all finite y<0. The
32722 * if-clause also catches y == -Infinity (which works even
32723 * without the fix).
32724 */
32725
32726 /* fmod() return value has same sign as input (negative) so
32727 * the result here will be in the range ]-2,0], 1 indicates
32728 * odd. If x is -Infinity, NaN is returned and the odd check
32729 * always concludes "not odd" which results in desired outcome.
32730 */
32731 double tmp = DUK_FMOD(y, 2);
32732 if (tmp == -1.0) {
32733 return -DUK_DOUBLE_INFINITY;
32734 } else {
32735 /* Not odd, or y == -Infinity */
32736 return DUK_DOUBLE_INFINITY;
32737 }
32738 }
32739 }
32740#endif
32741 return DUK_POW(x, y);
32742
32743 ret_nan:
32744 return DUK_DOUBLE_NAN;
32745}
32746
32747/* Wrappers for calling standard math library methods. These may be required
32748 * on platforms where one or more of the math built-ins are defined as macros
32749 * or inline functions and are thus not suitable to be used as function pointers.
32750 */
32751#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
32752DUK_LOCAL double duk__fabs(double x) {
32753 return DUK_FABS(x);
32754}
32755DUK_LOCAL double duk__acos(double x) {
32756 return DUK_ACOS(x);
32757}
32758DUK_LOCAL double duk__asin(double x) {
32759 return DUK_ASIN(x);
32760}
32761DUK_LOCAL double duk__atan(double x) {
32762 return DUK_ATAN(x);
32763}
32764DUK_LOCAL double duk__ceil(double x) {
32765 return DUK_CEIL(x);
32766}
32767DUK_LOCAL double duk__cos(double x) {
32768 return DUK_COS(x);
32769}
32770DUK_LOCAL double duk__exp(double x) {
32771 return DUK_EXP(x);
32772}
32773DUK_LOCAL double duk__floor(double x) {
32774 return DUK_FLOOR(x);
32775}
32776DUK_LOCAL double duk__log(double x) {
32777 return DUK_LOG(x);
32778}
32779DUK_LOCAL double duk__sin(double x) {
32780 return DUK_SIN(x);
32781}
32782DUK_LOCAL double duk__sqrt(double x) {
32783 return DUK_SQRT(x);
32784}
32785DUK_LOCAL double duk__tan(double x) {
32786 return DUK_TAN(x);
32787}
32788DUK_LOCAL double duk__atan2(double x, double y) {
32789 return DUK_ATAN2(x, y);
32790}
32791#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
32792
32793/* order must match constants in genbuiltins.py */
32794DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
32795#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
32796 duk__fabs,
32797 duk__acos,
32798 duk__asin,
32799 duk__atan,
32800 duk__ceil,
32801 duk__cos,
32802 duk__exp,
32803 duk__floor,
32804 duk__log,
32805 duk__round_fixed,
32806 duk__sin,
32807 duk__sqrt,
32808 duk__tan
32809#else
32810 DUK_FABS,
32811 DUK_ACOS,
32812 DUK_ASIN,
32813 DUK_ATAN,
32814 DUK_CEIL,
32815 DUK_COS,
32816 DUK_EXP,
32817 DUK_FLOOR,
32818 DUK_LOG,
32819 duk__round_fixed,
32820 DUK_SIN,
32821 DUK_SQRT,
32822 DUK_TAN
32823#endif
32824};
32825
32826/* order must match constants in genbuiltins.py */
32827DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
32828#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
32829 duk__atan2,
32830 duk__pow_fixed
32831#else
32832 DUK_ATAN2,
32833 duk__pow_fixed
32834#endif
32835};
32836
32837DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
32838 duk_small_int_t fun_idx = duk_get_current_magic(ctx);
32839 duk__one_arg_func fun;
32840
32841 DUK_ASSERT(fun_idx >= 0);
32842 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
32843 fun = duk__one_arg_funcs[fun_idx];
32844 duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0)));
32845 return 1;
32846}
32847
32848DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
32849 duk_small_int_t fun_idx = duk_get_current_magic(ctx);
32850 duk__two_arg_func fun;
32851
32852 DUK_ASSERT(fun_idx >= 0);
32853 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
32854 fun = duk__two_arg_funcs[fun_idx];
32855 duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0), (double) duk_to_number(ctx, 1)));
32856 return 1;
32857}
32858
32859DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
32860 return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
32861}
32862
32863DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
32864 return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
32865}
32866
32867DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
32868 duk_push_number(ctx, (duk_double_t) duk_util_tinyrandom_get_double((duk_hthread *) ctx));
32869 return 1;
32870}
32871
32872#else /* DUK_USE_MATH_BUILTIN */
32873
32874/* A stubbed built-in is useful for e.g. compilation torture testing with BCC. */
32875
32876DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
32877 DUK_UNREF(ctx);
32878 return DUK_RET_UNIMPLEMENTED_ERROR;
32879}
32880
32881DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
32882 DUK_UNREF(ctx);
32883 return DUK_RET_UNIMPLEMENTED_ERROR;
32884}
32885
32886DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
32887 DUK_UNREF(ctx);
32888 return DUK_RET_UNIMPLEMENTED_ERROR;
32889}
32890
32891DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
32892 DUK_UNREF(ctx);
32893 return DUK_RET_UNIMPLEMENTED_ERROR;
32894}
32895
32896DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
32897 DUK_UNREF(ctx);
32898 return DUK_RET_UNIMPLEMENTED_ERROR;
32899}
32900
32901#endif /* DUK_USE_MATH_BUILTIN */
32902#line 1 "duk_bi_number.c"
32903/*
32904 * Number built-ins
32905 */
32906
32907/* include removed: duk_internal.h */
32908
32909DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_context *ctx) {
32910 duk_hobject *h;
32911
32912 /* Number built-in accepts a plain number or a Number object (whose
32913 * internal value is operated on). Other types cause TypeError.
32914 */
32915
32916 duk_push_this(ctx);
32917 if (duk_is_number(ctx, -1)) {
32918 DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
32919 goto done;
32920 }
32921 h = duk_get_hobject(ctx, -1);
32922 if (!h ||
32923 (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
32924 DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
32925 DUK_ERROR_TYPE((duk_hthread *) ctx, "number expected");
32926 }
32927 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
32928 DUK_ASSERT(duk_is_number(ctx, -1));
32929 DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
32930 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
32931 duk_remove(ctx, -2);
32932
32933 done:
32934 return duk_get_number(ctx, -1);
32935}
32936
32937DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
32938 duk_hthread *thr = (duk_hthread *) ctx;
32939 duk_idx_t nargs;
32940 duk_hobject *h_this;
32941
32942 DUK_UNREF(thr);
32943
32944 /*
32945 * The Number constructor uses ToNumber(arg) for number coercion
32946 * (coercing an undefined argument to NaN). However, if the
32947 * argument is not given at all, +0 must be used instead. To do
32948 * this, a vararg function is used.
32949 */
32950
32951 nargs = duk_get_top(ctx);
32952 if (nargs == 0) {
32953 duk_push_int(ctx, 0);
32954 }
32955 duk_to_number(ctx, 0);
32956 duk_set_top(ctx, 1);
32957 DUK_ASSERT_TOP(ctx, 1);
32958
32959 if (!duk_is_constructor_call(ctx)) {
32960 return 1;
32961 }
32962
32963 /*
32964 * E5 Section 15.7.2.1 requires that the constructed object
32965 * must have the original Number.prototype as its internal
32966 * prototype. However, since Number.prototype is non-writable
32967 * and non-configurable, this doesn't have to be enforced here:
32968 * The default object (bound to 'this') is OK, though we have
32969 * to change its class.
32970 *
32971 * Internal value set to ToNumber(arg) or +0; if no arg given,
32972 * ToNumber(undefined) = NaN, so special treatment is needed
32973 * (above). String internal value is immutable.
32974 */
32975
32976 /* XXX: helper */
32977 duk_push_this(ctx);
32978 h_this = duk_get_hobject(ctx, -1);
32979 DUK_ASSERT(h_this != NULL);
32980 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
32981
32982 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
32983 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
32984 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
32985
32986 duk_dup(ctx, 0); /* -> [ val obj val ] */
32987 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
32988 return 0; /* no return value -> don't replace created value */
32989}
32990
32991DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx) {
32992 (void) duk__push_this_number_plain(ctx);
32993 return 1;
32994}
32995
32996DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx) {
32997 duk_small_int_t radix;
32998 duk_small_uint_t n2s_flags;
32999
33000 (void) duk__push_this_number_plain(ctx);
33001 if (duk_is_undefined(ctx, 0)) {
33002 radix = 10;
33003 } else {
33004 radix = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 2, 36);
33005 }
33006 DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
33007
33008 n2s_flags = 0;
33009
33010 duk_numconv_stringify(ctx,
33011 radix /*radix*/,
33012 0 /*digits*/,
33013 n2s_flags /*flags*/);
33014 return 1;
33015}
33016
33017DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx) {
33018 /* XXX: just use toString() for now; permitted although not recommended.
33019 * nargs==1, so radix is passed to toString().
33020 */
33021 return duk_bi_number_prototype_to_string(ctx);
33022}
33023
33024/*
33025 * toFixed(), toExponential(), toPrecision()
33026 */
33027
33028/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
33029
33030DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
33031 duk_small_int_t frac_digits;
33032 duk_double_t d;
33033 duk_small_int_t c;
33034 duk_small_uint_t n2s_flags;
33035
33036 frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
33037 d = duk__push_this_number_plain(ctx);
33038
33039 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
33040 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
33041 goto use_to_string;
33042 }
33043
33044 if (d >= 1.0e21 || d <= -1.0e21) {
33045 goto use_to_string;
33046 }
33047
33048 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
33049 DUK_N2S_FLAG_FRACTION_DIGITS;
33050
33051 duk_numconv_stringify(ctx,
33052 10 /*radix*/,
33053 frac_digits /*digits*/,
33054 n2s_flags /*flags*/);
33055 return 1;
33056
33057 use_to_string:
33058 DUK_ASSERT_TOP(ctx, 2);
33059 duk_to_string(ctx, -1);
33060 return 1;
33061}
33062
33063DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx) {
33064 duk_bool_t frac_undefined;
33065 duk_small_int_t frac_digits;
33066 duk_double_t d;
33067 duk_small_int_t c;
33068 duk_small_uint_t n2s_flags;
33069
33070 d = duk__push_this_number_plain(ctx);
33071
33072 frac_undefined = duk_is_undefined(ctx, 0);
33073 duk_to_int(ctx, 0); /* for side effects */
33074
33075 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
33076 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
33077 goto use_to_string;
33078 }
33079
33080 frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
33081
33082 n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
33083 (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
33084
33085 duk_numconv_stringify(ctx,
33086 10 /*radix*/,
33087 frac_digits + 1 /*leading digit + fractions*/,
33088 n2s_flags /*flags*/);
33089 return 1;
33090
33091 use_to_string:
33092 DUK_ASSERT_TOP(ctx, 2);
33093 duk_to_string(ctx, -1);
33094 return 1;
33095}
33096
33097DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
33098 /* The specification has quite awkward order of coercion and
33099 * checks for toPrecision(). The operations below are a bit
33100 * reordered, within constraints of observable side effects.
33101 */
33102
33103 duk_double_t d;
33104 duk_small_int_t prec;
33105 duk_small_int_t c;
33106 duk_small_uint_t n2s_flags;
33107
33108 DUK_ASSERT_TOP(ctx, 1);
33109
33110 d = duk__push_this_number_plain(ctx);
33111 if (duk_is_undefined(ctx, 0)) {
33112 goto use_to_string;
33113 }
33114 DUK_ASSERT_TOP(ctx, 2);
33115
33116 duk_to_int(ctx, 0); /* for side effects */
33117
33118 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
33119 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
33120 goto use_to_string;
33121 }
33122
33123 prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21);
33124
33125 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
33126 DUK_N2S_FLAG_NO_ZERO_PAD;
33127
33128 duk_numconv_stringify(ctx,
33129 10 /*radix*/,
33130 prec /*digits*/,
33131 n2s_flags /*flags*/);
33132 return 1;
33133
33134 use_to_string:
33135 /* Used when precision is undefined; also used for NaN (-> "NaN"),
33136 * and +/- infinity (-> "Infinity", "-Infinity").
33137 */
33138
33139 DUK_ASSERT_TOP(ctx, 2);
33140 duk_to_string(ctx, -1);
33141 return 1;
33142}
33143#line 1 "duk_bi_object.c"
33144/*
33145 * Object built-ins
33146 */
33147
33148/* include removed: duk_internal.h */
33149
33150DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
33151 if (!duk_is_constructor_call(ctx) &&
33152 !duk_is_null_or_undefined(ctx, 0)) {
33153 duk_to_object(ctx, 0);
33154 return 1;
33155 }
33156
33157 if (duk_is_object(ctx, 0)) {
33158 return 1;
33159 }
33160
33161 /* Pointer and buffer primitive values are treated like other
33162 * primitives values which have a fully fledged object counterpart:
33163 * promote to an object value. Lightfuncs are coerced with
33164 * ToObject() even they could also be returned as is.
33165 */
33166 if (duk_check_type_mask(ctx, 0, DUK_TYPE_MASK_STRING |
33167 DUK_TYPE_MASK_BOOLEAN |
33168 DUK_TYPE_MASK_NUMBER |
33169 DUK_TYPE_MASK_POINTER |
33170 DUK_TYPE_MASK_BUFFER |
33171 DUK_TYPE_MASK_LIGHTFUNC)) {
33172 duk_to_object(ctx, 0);
33173 return 1;
33174 }
33175
33176 duk_push_object_helper(ctx,
33177 DUK_HOBJECT_FLAG_EXTENSIBLE |
33178 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
33179 DUK_BIDX_OBJECT_PROTOTYPE);
33180 return 1;
33181}
33182
33183/* Shared helper to implement Object.getPrototypeOf and the ES6
33184 * Object.prototype.__proto__ getter.
33185 *
33186 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
33187 */
33188DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
33189 duk_hthread *thr = (duk_hthread *) ctx;
33190 duk_hobject *h;
33191 duk_hobject *proto;
33192
33193 DUK_UNREF(thr);
33194
33195 /* magic: 0=getter call, 1=Object.getPrototypeOf */
33196 if (duk_get_current_magic(ctx) == 0) {
33197 duk_push_this_coercible_to_object(ctx);
33198 duk_insert(ctx, 0);
33199 }
33200
33201 h = duk_require_hobject_or_lfunc(ctx, 0);
33202 /* h is NULL for lightfunc */
33203
33204 /* XXX: should the API call handle this directly, i.e. attempt
33205 * to duk_push_hobject(ctx, null) would push a null instead?
33206 * (On the other hand 'undefined' would be just as logical, but
33207 * not wanted here.)
33208 */
33209
33210 if (h == NULL) {
33211 duk_push_hobject_bidx(ctx, DUK_BIDX_FUNCTION_PROTOTYPE);
33212 } else {
33213 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
33214 if (proto) {
33215 duk_push_hobject(ctx, proto);
33216 } else {
33217 duk_push_null(ctx);
33218 }
33219 }
33220 return 1;
33221}
33222
33223/* Shared helper to implement ES6 Object.setPrototypeOf and
33224 * Object.prototype.__proto__ setter.
33225 *
33226 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
33227 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
33228 */
33229DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
33230 duk_hthread *thr = (duk_hthread *) ctx;
33231 duk_hobject *h_obj;
33232 duk_hobject *h_new_proto;
33233 duk_hobject *h_curr;
33234 duk_ret_t ret_success = 1; /* retval for success path */
33235
33236 /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4);
33237 * magic: 0=setter call, 1=Object.setPrototypeOf
33238 */
33239 if (duk_get_current_magic(ctx) == 0) {
33240 duk_push_this_check_object_coercible(ctx);
33241 duk_insert(ctx, 0);
33242 if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
33243 return 0;
33244 }
33245
33246 /* __proto__ setter returns 'undefined' on success unlike the
33247 * setPrototypeOf() call which returns the target object.
33248 */
33249 ret_success = 0;
33250 } else {
33251 duk_require_object_coercible(ctx, 0);
33252 duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
33253 }
33254
33255 h_new_proto = duk_get_hobject(ctx, 1);
33256 /* h_new_proto may be NULL */
33257 if (duk_is_lightfunc(ctx, 0)) {
33258 if (h_new_proto == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]) {
33259 goto skip;
33260 }
33261 goto fail_nonextensible;
33262 }
33263 h_obj = duk_get_hobject(ctx, 0);
33264 if (!h_obj) {
33265 goto skip;
33266 }
33267 DUK_ASSERT(h_obj != NULL);
33268
33269 /* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */
33270 /* TODO: implement Proxy object support here */
33271
33272 if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
33273 goto skip;
33274 }
33275 if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
33276 goto fail_nonextensible;
33277 }
33278 for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
33279 /* Loop prevention */
33280 if (h_curr == h_obj) {
33281 goto fail_loop;
33282 }
33283 }
33284 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
33285 /* fall thru */
33286
33287 skip:
33288 duk_set_top(ctx, 1);
33289 return ret_success;
33290
33291 fail_nonextensible:
33292 fail_loop:
33293 return DUK_RET_TYPE_ERROR;
33294}
33295
33296DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
33297 /* XXX: no need for indirect call */
33298 return duk_hobject_object_get_own_property_descriptor(ctx);
33299}
33300
33301DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
33302 duk_tval *tv;
33303 duk_hobject *proto = NULL;
33304
33305 DUK_ASSERT_TOP(ctx, 2);
33306
33307 tv = duk_get_tval(ctx, 0);
33308 DUK_ASSERT(tv != NULL);
33309 if (DUK_TVAL_IS_NULL(tv)) {
33310 ;
33311 } else if (DUK_TVAL_IS_OBJECT(tv)) {
33312 proto = DUK_TVAL_GET_OBJECT(tv);
33313 DUK_ASSERT(proto != NULL);
33314 } else {
33315 return DUK_RET_TYPE_ERROR;
33316 }
33317
33318 (void) duk_push_object_helper_proto(ctx,
33319 DUK_HOBJECT_FLAG_EXTENSIBLE |
33320 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
33321 proto);
33322
33323 if (!duk_is_undefined(ctx, 1)) {
33324 /* [ O Properties obj ] */
33325
33326 duk_replace(ctx, 0);
33327
33328 /* [ obj Properties ] */
33329
33330 /* Just call the "original" Object.defineProperties() to
33331 * finish up.
33332 */
33333
33334 return duk_bi_object_constructor_define_properties(ctx);
33335 }
33336
33337 /* [ O Properties obj ] */
33338
33339 return 1;
33340}
33341
33342DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
33343 duk_hobject *obj;
33344 duk_hstring *key;
33345 duk_hobject *get;
33346 duk_hobject *set;
33347 duk_idx_t idx_value;
33348 duk_uint_t defprop_flags;
33349
33350 DUK_ASSERT(ctx != NULL);
33351
33352 DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
33353 (void *) ctx,
33354 (duk_tval *) duk_get_tval(ctx, 0),
33355 (duk_tval *) duk_get_tval(ctx, 1),
33356 (duk_tval *) duk_get_tval(ctx, 2)));
33357
33358 /* [ obj key desc ] */
33359
33360 /* Lightfuncs are currently supported by coercing to a temporary
33361 * Function object; changes will be allowed (the coerced value is
33362 * extensible) but will be lost.
33363 */
33364 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
33365 (void) duk_to_string(ctx, 1);
33366 key = duk_require_hstring(ctx, 1);
33367 (void) duk_require_hobject(ctx, 2);
33368
33369 DUK_ASSERT(obj != NULL);
33370 DUK_ASSERT(key != NULL);
33371 DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);
33372
33373 /*
33374 * Validate and convert argument property descriptor (an Ecmascript
33375 * object) into a set of defprop_flags and possibly property value,
33376 * getter, and/or setter values on the value stack.
33377 *
33378 * Lightfunc set/get values are coerced to full Functions.
33379 */
33380
33381 duk_hobject_prepare_property_descriptor(ctx,
33382 2 /*idx_desc*/,
33383 &defprop_flags,
33384 &idx_value,
33385 &get,
33386 &set);
33387
33388 /*
33389 * Use Object.defineProperty() helper for the actual operation.
33390 */
33391
33392 duk_hobject_define_property_helper(ctx,
33393 defprop_flags,
33394 obj,
33395 key,
33396 idx_value,
33397 get,
33398 set);
33399
33400 /* Ignore the normalize/validate helper outputs on the value stack,
33401 * they're popped automatically.
33402 */
33403
33404 /*
33405 * Return target object.
33406 */
33407
33408 duk_push_hobject(ctx, obj);
33409 return 1;
33410}
33411
33412DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
33413 duk_small_uint_t pass;
33414 duk_uint_t defprop_flags;
33415 duk_hobject *obj;
33416 duk_idx_t idx_value;
33417 duk_hobject *get;
33418 duk_hobject *set;
33419
33420 /* Lightfunc handling by ToObject() coercion. */
33421 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0); /* target */
33422 DUK_ASSERT(obj != NULL);
33423
33424 duk_to_object(ctx, 1); /* properties object */
33425
33426 DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
33427 (duk_tval *) duk_get_tval(ctx, 0),
33428 (duk_tval *) duk_get_tval(ctx, 1)));
33429
33430 /*
33431 * Two pass approach to processing the property descriptors.
33432 * On first pass validate and normalize all descriptors before
33433 * any changes are made to the target object. On second pass
33434 * make the actual modifications to the target object.
33435 *
33436 * Right now we'll just use the same normalize/validate helper
33437 * on both passes, ignoring its outputs on the first pass.
33438 */
33439
33440 for (pass = 0; pass < 2; pass++) {
33441 duk_set_top(ctx, 2); /* -> [ hobject props ] */
33442 duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY /*enum_flags*/);
33443
33444 for (;;) {
33445 duk_hstring *key;
33446
33447 /* [ hobject props enum(props) ] */
33448
33449 duk_set_top(ctx, 3);
33450
33451 if (!duk_next(ctx, 2, 1 /*get_value*/)) {
33452 break;
33453 }
33454
33455 DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
33456 (duk_tval *) duk_get_tval(ctx, -2),
33457 (duk_tval *) duk_get_tval(ctx, -1)));
33458
33459 /* [ hobject props enum(props) key desc ] */
33460
33461 duk_hobject_prepare_property_descriptor(ctx,
33462 4 /*idx_desc*/,
33463 &defprop_flags,
33464 &idx_value,
33465 &get,
33466 &set);
33467
33468 /* [ hobject props enum(props) key desc value? getter? setter? ] */
33469
33470 if (pass == 0) {
33471 continue;
33472 }
33473
33474 key = duk_get_hstring(ctx, 3);
33475 DUK_ASSERT(key != NULL);
33476
33477 duk_hobject_define_property_helper(ctx,
33478 defprop_flags,
33479 obj,
33480 key,
33481 idx_value,
33482 get,
33483 set);
33484 }
33485 }
33486
33487 /*
33488 * Return target object
33489 */
33490
33491 duk_dup(ctx, 0);
33492 return 1;
33493}
33494
33495DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
33496 duk_hthread *thr = (duk_hthread *) ctx;
33497 duk_hobject *h;
33498 duk_bool_t is_freeze;
33499
33500 h = duk_require_hobject_or_lfunc(ctx, 0);
33501 if (!h) {
33502 /* Lightfunc, always success. */
33503 return 1;
33504 }
33505
33506 is_freeze = (duk_bool_t) duk_get_current_magic(ctx);
33507 duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
33508
33509 /* Sealed and frozen objects cannot gain any more properties,
33510 * so this is a good time to compact them.
33511 */
33512 duk_hobject_compact_props(thr, h);
33513
33514 return 1;
33515}
33516
33517DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
33518 duk_hthread *thr = (duk_hthread *) ctx;
33519 duk_hobject *h;
33520
33521 h = duk_require_hobject_or_lfunc(ctx, 0);
33522 if (!h) {
33523 /* Lightfunc, always success. */
33524 return 1;
33525 }
33526 DUK_ASSERT(h != NULL);
33527
33528 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
33529
33530 /* A non-extensible object cannot gain any more properties,
33531 * so this is a good time to compact.
33532 */
33533 duk_hobject_compact_props(thr, h);
33534
33535 return 1;
33536}
33537
33538DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
33539 duk_hobject *h;
33540 duk_bool_t is_frozen;
33541 duk_bool_t rc;
33542
33543 h = duk_require_hobject_or_lfunc(ctx, 0);
33544 if (!h) {
33545 duk_push_true(ctx); /* frozen and sealed */
33546 } else {
33547 is_frozen = duk_get_current_magic(ctx);
33548 rc = duk_hobject_object_is_sealed_frozen_helper((duk_hthread *) ctx, h, is_frozen /*is_frozen*/);
33549 duk_push_boolean(ctx, rc);
33550 }
33551 return 1;
33552}
33553
33554DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
33555 duk_hobject *h;
33556
33557 h = duk_require_hobject_or_lfunc(ctx, 0);
33558 if (!h) {
33559 duk_push_false(ctx);
33560 } else {
33561 duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h));
33562 }
33563 return 1;
33564}
33565
33566/* Shared helper for Object.getOwnPropertyNames() and Object.keys().
33567 * Magic: 0=getOwnPropertyNames, 1=Object.keys.
33568 */
33569DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
33570 duk_hthread *thr = (duk_hthread *) ctx;
33571 duk_hobject *obj;
33572#if defined(DUK_USE_ES6_PROXY)
33573 duk_hobject *h_proxy_target;
33574 duk_hobject *h_proxy_handler;
33575 duk_hobject *h_trap_result;
33576 duk_uarridx_t i, len, idx;
33577#endif
33578 duk_small_uint_t enum_flags;
33579
33580 DUK_ASSERT_TOP(ctx, 1);
33581 DUK_UNREF(thr);
33582
33583 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
33584 DUK_ASSERT(obj != NULL);
33585 DUK_UNREF(obj);
33586
33587#if defined(DUK_USE_ES6_PROXY)
33588 if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
33589 obj,
33590 &h_proxy_target,
33591 &h_proxy_handler))) {
33592 goto skip_proxy;
33593 }
33594
33595 duk_push_hobject(ctx, h_proxy_handler);
33596 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
33597 /* Careful with reachability here: don't pop 'obj' before pushing
33598 * proxy target.
33599 */
33600 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
33601 duk_pop_2(ctx);
33602 duk_push_hobject(ctx, h_proxy_target);
33603 duk_replace(ctx, 0);
33604 DUK_ASSERT_TOP(ctx, 1);
33605 goto skip_proxy;
33606 }
33607
33608 /* [ obj handler trap ] */
33609 duk_insert(ctx, -2);
33610 duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */
33611 duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */
33612 h_trap_result = duk_require_hobject(ctx, -1);
33613 DUK_UNREF(h_trap_result);
33614
33615 len = (duk_uarridx_t) duk_get_length(ctx, -1);
33616 idx = 0;
33617 duk_push_array(ctx);
33618 for (i = 0; i < len; i++) {
33619 /* [ obj trap_result res_arr ] */
33620 if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) {
33621 /* XXX: for Object.keys() we should check enumerability of key */
33622 /* [ obj trap_result res_arr propname ] */
33623 duk_put_prop_index(ctx, -2, idx);
33624 idx++;
33625 } else {
33626 duk_pop(ctx);
33627 }
33628 }
33629
33630 /* XXX: missing trap result validation for non-configurable target keys
33631 * (must be present), for non-extensible target all target keys must be
33632 * present and no extra keys can be present.
33633 * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
33634 */
33635
33636 /* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result)
33637 * should be filtered so that only enumerable keys remain. Enumerability
33638 * should be checked with [[GetOwnProperty]] on the original object
33639 * (i.e., the proxy in this case). If the proxy has a getOwnPropertyDescriptor
33640 * trap, it should be triggered for every property. If the proxy doesn't have
33641 * the trap, enumerability should be checked against the target object instead.
33642 * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames()
33643 * return the same result now for proxy traps. We still do clean up the trap
33644 * result, so that Object.keys() and Object.getOwnPropertyNames() will return a
33645 * clean array of strings without gaps.
33646 */
33647 return 1;
33648
33649 skip_proxy:
33650#endif /* DUK_USE_ES6_PROXY */
33651
33652 DUK_ASSERT_TOP(ctx, 1);
33653
33654 if (duk_get_current_magic(ctx)) {
33655 /* Object.keys */
33656 enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY |
33657 DUK_ENUM_NO_PROXY_BEHAVIOR;
33658 } else {
33659 /* Object.getOwnPropertyNames */
33660 enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE |
33661 DUK_ENUM_OWN_PROPERTIES_ONLY |
33662 DUK_ENUM_NO_PROXY_BEHAVIOR;
33663 }
33664
33665 return duk_hobject_get_enumerated_keys(ctx, enum_flags);
33666}
33667
33668DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
33669 duk_push_this(ctx);
33670 duk_to_object_class_string_top(ctx);
33671 return 1;
33672}
33673
33674DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
33675 DUK_ASSERT_TOP(ctx, 0);
33676 (void) duk_push_this_coercible_to_object(ctx);
33677 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING);
33678 if (!duk_is_callable(ctx, 1)) {
33679 return DUK_RET_TYPE_ERROR;
33680 }
33681 duk_dup(ctx, 0); /* -> [ O toString O ] */
33682 duk_call_method(ctx, 0); /* XXX: call method tail call? */
33683 return 1;
33684}
33685
33686DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
33687 (void) duk_push_this_coercible_to_object(ctx);
33688 return 1;
33689}
33690
33691DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
33692 duk_hthread *thr = (duk_hthread *) ctx;
33693 duk_hobject *h_v;
33694 duk_hobject *h_obj;
33695
33696 DUK_ASSERT_TOP(ctx, 1);
33697
33698 h_v = duk_get_hobject(ctx, 0);
33699 if (!h_v) {
33700 duk_push_false(ctx); /* XXX: tail call: return duk_push_false(ctx) */
33701 return 1;
33702 }
33703
33704 h_obj = duk_push_this_coercible_to_object(ctx);
33705 DUK_ASSERT(h_obj != NULL);
33706
33707 /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
33708 * Prototype loops should cause an error to be thrown.
33709 */
33710 duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
33711 return 1;
33712}
33713
33714DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
33715 return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
33716}
33717
33718DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
33719 return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
33720}
33721#line 1 "duk_bi_pointer.c"
33722/*
33723 * Pointer built-ins
33724 */
33725
33726/* include removed: duk_internal.h */
33727
33728/*
33729 * Constructor
33730 */
33731
33732DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
33733 /* XXX: this behavior is quite useless now; it would be nice to be able
33734 * to create pointer values from e.g. numbers or strings. Numbers are
33735 * problematic on 64-bit platforms though. Hex encoded strings?
33736 */
33737 if (duk_get_top(ctx) == 0) {
33738 duk_push_pointer(ctx, NULL);
33739 } else {
33740 duk_to_pointer(ctx, 0);
33741 }
33742 DUK_ASSERT(duk_is_pointer(ctx, 0));
33743 duk_set_top(ctx, 1);
33744
33745 if (duk_is_constructor_call(ctx)) {
33746 duk_push_object_helper(ctx,
33747 DUK_HOBJECT_FLAG_EXTENSIBLE |
33748 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
33749 DUK_BIDX_POINTER_PROTOTYPE);
33750
33751 /* Pointer object internal value is immutable */
33752 duk_dup(ctx, 0);
33753 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
33754 }
33755 /* Note: unbalanced stack on purpose */
33756
33757 return 1;
33758}
33759
33760/*
33761 * toString(), valueOf()
33762 */
33763
33764DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx) {
33765 duk_tval *tv;
33766 duk_small_int_t to_string = duk_get_current_magic(ctx);
33767
33768 duk_push_this(ctx);
33769 tv = duk_require_tval(ctx, -1);
33770 DUK_ASSERT(tv != NULL);
33771
33772 if (DUK_TVAL_IS_POINTER(tv)) {
33773 /* nop */
33774 } else if (DUK_TVAL_IS_OBJECT(tv)) {
33775 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
33776 DUK_ASSERT(h != NULL);
33777
33778 /* Must be a "pointer object", i.e. class "Pointer" */
33779 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
33780 goto type_error;
33781 }
33782
33783 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
33784 } else {
33785 goto type_error;
33786 }
33787
33788 if (to_string) {
33789 duk_to_string(ctx, -1);
33790 }
33791 return 1;
33792
33793 type_error:
33794 return DUK_RET_TYPE_ERROR;
33795}
33796#line 1 "duk_bi_proxy.c"
33797/*
33798 * Proxy built-in (ES6)
33799 */
33800
33801/* include removed: duk_internal.h */
33802
33803#if defined(DUK_USE_ES6_PROXY)
33804DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
33805 duk_hobject *h_target;
33806 duk_hobject *h_handler;
33807
33808 if (!duk_is_constructor_call(ctx)) {
33809 return DUK_RET_TYPE_ERROR;
33810 }
33811
33812 /* Reject a proxy object as the target because it would need
33813 * special handler in property lookups. (ES6 has no such restriction)
33814 */
33815 h_target = duk_require_hobject_or_lfunc_coerce(ctx, 0);
33816 DUK_ASSERT(h_target != NULL);
33817 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) {
33818 return DUK_RET_TYPE_ERROR;
33819 }
33820
33821 /* Reject a proxy object as the handler because it would cause
33822 * potentially unbounded recursion. (ES6 has no such restriction)
33823 */
33824 h_handler = duk_require_hobject_or_lfunc_coerce(ctx, 1);
33825 DUK_ASSERT(h_handler != NULL);
33826 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) {
33827 return DUK_RET_TYPE_ERROR;
33828 }
33829
33830 /* XXX: the returned value is exotic in ES6, but we use a
33831 * simple object here with no prototype. Without a prototype,
33832 * [[DefaultValue]] coercion fails which is abit confusing.
33833 * No callable check/handling in the current Proxy subset.
33834 */
33835 (void) duk_push_object_helper_proto(ctx,
33836 DUK_HOBJECT_FLAG_EXTENSIBLE |
33837 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ |
33838 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
33839 NULL);
33840 DUK_ASSERT_TOP(ctx, 3);
33841
33842 /* Make _Target and _Handler non-configurable and non-writable.
33843 * They can still be forcibly changed by C code (both user and
33844 * Duktape internal), but not by Ecmascript code.
33845 */
33846
33847 /* Proxy target */
33848 duk_dup(ctx, 0);
33849 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
33850
33851 /* Proxy handler */
33852 duk_dup(ctx, 1);
33853 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE);
33854
33855 return 1; /* replacement handler */
33856}
33857#else /* DUK_USE_ES6_PROXY */
33858DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
33859 DUK_UNREF(ctx);
33860 return DUK_RET_UNSUPPORTED_ERROR;
33861}
33862#endif /* DUK_USE_ES6_PROXY */
33863#line 1 "duk_bi_regexp.c"
33864/*
33865 * RegExp built-ins
33866 */
33867
33868/* include removed: duk_internal.h */
33869
33870#ifdef DUK_USE_REGEXP_SUPPORT
33871
33872DUK_LOCAL void duk__get_this_regexp(duk_context *ctx) {
33873 duk_hobject *h;
33874
33875 duk_push_this(ctx);
33876 h = duk_require_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_REGEXP);
33877 DUK_ASSERT(h != NULL);
33878 DUK_UNREF(h);
33879 duk_insert(ctx, 0); /* prepend regexp to valstack 0 index */
33880}
33881
33882/* XXX: much to improve (code size) */
33883DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
33884 duk_hthread *thr = (duk_hthread *) ctx;
33885 duk_hobject *h_pattern;
33886
33887 DUK_ASSERT_TOP(ctx, 2);
33888 h_pattern = duk_get_hobject(ctx, 0);
33889
33890 if (!duk_is_constructor_call(ctx) &&
33891 h_pattern != NULL &&
33892 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
33893 duk_is_undefined(ctx, 1)) {
33894 /* Called as a function, pattern has [[Class]] "RegExp" and
33895 * flags is undefined -> return object as is.
33896 */
33897 duk_dup(ctx, 0);
33898 return 1;
33899 }
33900
33901 /* Else functionality is identical for function call and constructor
33902 * call.
33903 */
33904
33905 if (h_pattern != NULL &&
33906 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
33907 if (duk_is_undefined(ctx, 1)) {
33908 duk_bool_t flag_g, flag_i, flag_m;
33909 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
33910 flag_g = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
33911 flag_i = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_IGNORE_CASE, NULL);
33912 flag_m = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_MULTILINE, NULL);
33913
33914 duk_push_sprintf(ctx, "%s%s%s",
33915 (const char *) (flag_g ? "g" : ""),
33916 (const char *) (flag_i ? "i" : ""),
33917 (const char *) (flag_m ? "m" : ""));
33918
33919 /* [ ... pattern flags ] */
33920 } else {
33921 return DUK_RET_TYPE_ERROR;
33922 }
33923 } else {
33924 if (duk_is_undefined(ctx, 0)) {
33925 duk_push_string(ctx, "");
33926 } else {
33927 duk_dup(ctx, 0);
33928 duk_to_string(ctx, -1);
33929 }
33930 if (duk_is_undefined(ctx, 1)) {
33931 duk_push_string(ctx, "");
33932 } else {
33933 duk_dup(ctx, 1);
33934 duk_to_string(ctx, -1);
33935 }
33936
33937 /* [ ... pattern flags ] */
33938 }
33939
33940 DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
33941 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
33942
33943 /* [ ... pattern flags ] */
33944
33945 duk_regexp_compile(thr);
33946
33947 /* [ ... bytecode escaped_source ] */
33948
33949 duk_regexp_create_instance(thr);
33950
33951 /* [ ... RegExp ] */
33952
33953 return 1;
33954}
33955
33956DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
33957 duk__get_this_regexp(ctx);
33958
33959 /* [ regexp input ] */
33960
33961 duk_regexp_match((duk_hthread *) ctx);
33962
33963 /* [ result ] */
33964
33965 return 1;
33966}
33967
33968DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
33969 duk__get_this_regexp(ctx);
33970
33971 /* [ regexp input ] */
33972
33973 /* result object is created and discarded; wasteful but saves code space */
33974 duk_regexp_match((duk_hthread *) ctx);
33975
33976 /* [ result ] */
33977
33978 duk_push_boolean(ctx, (duk_is_null(ctx, -1) ? 0 : 1));
33979
33980 return 1;
33981}
33982
33983DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
33984 duk_hstring *h_bc;
33985 duk_small_int_t re_flags;
33986
33987#if 0
33988 /* A little tricky string approach to provide the flags string.
33989 * This depends on the specific flag values in duk_regexp.h,
33990 * which needs to be asserted for. In practice this doesn't
33991 * produce more compact code than the easier approach in use.
33992 */
33993
33994 const char *flag_strings = "gim\0gi\0gm\0g\0";
33995 duk_uint8_t flag_offsets[8] = {
33996 (duk_uint8_t) 3, /* flags: "" */
33997 (duk_uint8_t) 10, /* flags: "g" */
33998 (duk_uint8_t) 5, /* flags: "i" */
33999 (duk_uint8_t) 4, /* flags: "gi" */
34000 (duk_uint8_t) 2, /* flags: "m" */
34001 (duk_uint8_t) 7, /* flags: "gm" */
34002 (duk_uint8_t) 1, /* flags: "im" */
34003 (duk_uint8_t) 0, /* flags: "gim" */
34004 };
34005 DUK_ASSERT(DUK_RE_FLAG_GLOBAL == 1);
34006 DUK_ASSERT(DUK_RE_FLAG_IGNORE_CASE == 2);
34007 DUK_ASSERT(DUK_RE_FLAG_MULTILINE == 4);
34008#endif
34009
34010 duk__get_this_regexp(ctx);
34011
34012 /* [ regexp ] */
34013
34014 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
34015 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_BYTECODE);
34016 h_bc = duk_get_hstring(ctx, -1);
34017 DUK_ASSERT(h_bc != NULL);
34018 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1);
34019 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
34020 DUK_ASSERT(DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80);
34021 re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
34022
34023 /* [ regexp source bytecode ] */
34024
34025#if 1
34026 /* This is a cleaner approach and also produces smaller code than
34027 * the other alternative. Use duk_require_string() for format
34028 * safety (although the source property should always exist).
34029 */
34030 duk_push_sprintf(ctx, "/%s/%s%s%s",
34031 (const char *) duk_require_string(ctx, -2), /* require to be safe */
34032 (re_flags & DUK_RE_FLAG_GLOBAL) ? "g" : "",
34033 (re_flags & DUK_RE_FLAG_IGNORE_CASE) ? "i" : "",
34034 (re_flags & DUK_RE_FLAG_MULTILINE) ? "m" : "");
34035#else
34036 /* This should not be necessary because no-one should tamper with the
34037 * regexp bytecode, but is prudent to avoid potential segfaults if that
34038 * were to happen for some reason.
34039 */
34040 re_flags &= 0x07;
34041 DUK_ASSERT(re_flags >= 0 && re_flags <= 7); /* three flags */
34042 duk_push_sprintf(ctx, "/%s/%s",
34043 (const char *) duk_require_string(ctx, -2),
34044 (const char *) (flag_strings + flag_offsets[re_flags]));
34045#endif
34046
34047 return 1;
34048}
34049
34050#else /* DUK_USE_REGEXP_SUPPORT */
34051
34052DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
34053 DUK_UNREF(ctx);
34054 return DUK_RET_UNSUPPORTED_ERROR;
34055}
34056
34057DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
34058 DUK_UNREF(ctx);
34059 return DUK_RET_UNSUPPORTED_ERROR;
34060}
34061
34062DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
34063 DUK_UNREF(ctx);
34064 return DUK_RET_UNSUPPORTED_ERROR;
34065}
34066
34067DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
34068 DUK_UNREF(ctx);
34069 return DUK_RET_UNSUPPORTED_ERROR;
34070}
34071
34072#endif /* DUK_USE_REGEXP_SUPPORT */
34073#line 1 "duk_bi_string.c"
34074/*
34075 * String built-ins
34076 */
34077
34078/* XXX: There are several limitations in the current implementation for
34079 * strings with >= 0x80000000UL characters. In some cases one would need
34080 * to be able to represent the range [-0xffffffff,0xffffffff] and so on.
34081 * Generally character and byte length are assumed to fit into signed 32
34082 * bits (< 0x80000000UL). Places with issues are not marked explicitly
34083 * below in all cases, look for signed type usage (duk_int_t etc) for
34084 * offsets/lengths.
34085 */
34086
34087/* include removed: duk_internal.h */
34088
34089/*
34090 * Constructor
34091 */
34092
34093DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
34094 /* String constructor needs to distinguish between an argument not given at all
34095 * vs. given as 'undefined'. We're a vararg function to handle this properly.
34096 */
34097
34098 if (duk_get_top(ctx) == 0) {
34099 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
34100 } else {
34101 duk_to_string(ctx, 0);
34102 }
34103 DUK_ASSERT(duk_is_string(ctx, 0));
34104 duk_set_top(ctx, 1);
34105
34106 if (duk_is_constructor_call(ctx)) {
34107 duk_push_object_helper(ctx,
34108 DUK_HOBJECT_FLAG_EXTENSIBLE |
34109 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
34110 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING),
34111 DUK_BIDX_STRING_PROTOTYPE);
34112
34113 /* String object internal value is immutable */
34114 duk_dup(ctx, 0);
34115 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
34116 }
34117 /* Note: unbalanced stack on purpose */
34118
34119 return 1;
34120}
34121
34122DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx) {
34123 duk_hthread *thr = (duk_hthread *) ctx;
34124 duk_bufwriter_ctx bw_alloc;
34125 duk_bufwriter_ctx *bw;
34126 duk_idx_t i, n;
34127 duk_ucodepoint_t cp;
34128
34129 /* XXX: It would be nice to build the string directly but ToUint16()
34130 * coercion is needed so a generic helper would not be very
34131 * helpful (perhaps coerce the value stack first here and then
34132 * build a string from a duk_tval number sequence in one go?).
34133 */
34134
34135 n = duk_get_top(ctx);
34136
34137 bw = &bw_alloc;
34138 DUK_BW_INIT_PUSHBUF(thr, bw, n); /* initial estimate for ASCII only codepoints */
34139
34140 for (i = 0; i < n; i++) {
34141 /* XXX: could improve bufwriter handling to write multiple codepoints
34142 * with one ensure call but the relative benefit would be quite small.
34143 */
34144
34145#if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT)
34146 /* ToUint16() coercion is mandatory in the E5.1 specification, but
34147 * this non-compliant behavior makes more sense because we support
34148 * non-BMP codepoints. Don't use CESU-8 because that'd create
34149 * surrogate pairs.
34150 */
34151
34152 cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
34153 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
34154#else
34155 cp = (duk_ucodepoint_t) duk_to_uint16(ctx, i);
34156 DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
34157#endif
34158 }
34159
34160 DUK_BW_COMPACT(thr, bw);
34161 duk_to_string(ctx, -1);
34162 return 1;
34163}
34164
34165/*
34166 * toString(), valueOf()
34167 */
34168
34169DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
34170 duk_tval *tv;
34171
34172 duk_push_this(ctx);
34173 tv = duk_require_tval(ctx, -1);
34174 DUK_ASSERT(tv != NULL);
34175
34176 if (DUK_TVAL_IS_STRING(tv)) {
34177 /* return as is */
34178 return 1;
34179 } else if (DUK_TVAL_IS_OBJECT(tv)) {
34180 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
34181 DUK_ASSERT(h != NULL);
34182
34183 /* Must be a "string object", i.e. class "String" */
34184 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) {
34185 goto type_error;
34186 }
34187
34188 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
34189 DUK_ASSERT(duk_is_string(ctx, -1));
34190
34191 return 1;
34192 } else {
34193 goto type_error;
34194 }
34195
34196 /* never here, but fall through */
34197
34198 type_error:
34199 return DUK_RET_TYPE_ERROR;
34200}
34201
34202/*
34203 * Character and charcode access
34204 */
34205
34206DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx) {
34207 duk_int_t pos;
34208
34209 /* XXX: faster implementation */
34210
34211 (void) duk_push_this_coercible_to_string(ctx);
34212 pos = duk_to_int(ctx, 0);
34213 duk_substring(ctx, -1, pos, pos + 1);
34214 return 1;
34215}
34216
34217DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
34218 duk_hthread *thr = (duk_hthread *) ctx;
34219 duk_int_t pos;
34220 duk_hstring *h;
34221 duk_bool_t clamped;
34222
34223 /* XXX: faster implementation */
34224
34225 DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(ctx, 0)));
34226
34227 h = duk_push_this_coercible_to_string(ctx);
34228 DUK_ASSERT(h != NULL);
34229
34230 pos = duk_to_int_clamped_raw(ctx,
34231 0 /*index*/,
34232 0 /*min(incl)*/,
34233 DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
34234 &clamped /*out_clamped*/);
34235 if (clamped) {
34236 duk_push_number(ctx, DUK_DOUBLE_NAN);
34237 return 1;
34238 }
34239
34240 duk_push_u32(ctx, (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, pos));
34241 return 1;
34242}
34243
34244/*
34245 * substring(), substr(), slice()
34246 */
34247
34248/* XXX: any chance of merging these three similar but still slightly
34249 * different algorithms so that footprint would be reduced?
34250 */
34251
34252DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
34253 duk_hstring *h;
34254 duk_int_t start_pos, end_pos;
34255 duk_int_t len;
34256
34257 h = duk_push_this_coercible_to_string(ctx);
34258 DUK_ASSERT(h != NULL);
34259 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
34260
34261 /* [ start end str ] */
34262
34263 start_pos = duk_to_int_clamped(ctx, 0, 0, len);
34264 if (duk_is_undefined(ctx, 1)) {
34265 end_pos = len;
34266 } else {
34267 end_pos = duk_to_int_clamped(ctx, 1, 0, len);
34268 }
34269 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34270 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
34271
34272 if (start_pos > end_pos) {
34273 duk_int_t tmp = start_pos;
34274 start_pos = end_pos;
34275 end_pos = tmp;
34276 }
34277
34278 DUK_ASSERT(end_pos >= start_pos);
34279
34280 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
34281 return 1;
34282}
34283
34284#ifdef DUK_USE_SECTION_B
34285DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
34286 duk_hstring *h;
34287 duk_int_t start_pos, end_pos;
34288 duk_int_t len;
34289
34290 /* Unlike non-obsolete String calls, substr() algorithm in E5.1
34291 * specification will happily coerce undefined and null to strings
34292 * ("undefined" and "null").
34293 */
34294 duk_push_this(ctx);
34295 h = duk_to_hstring(ctx, -1);
34296 DUK_ASSERT(h != NULL);
34297 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
34298
34299 /* [ start length str ] */
34300
34301 /* The implementation for computing of start_pos and end_pos differs
34302 * from the standard algorithm, but is intended to result in the exactly
34303 * same behavior. This is not always obvious.
34304 */
34305
34306 /* combines steps 2 and 5; -len ensures max() not needed for step 5 */
34307 start_pos = duk_to_int_clamped(ctx, 0, -len, len);
34308 if (start_pos < 0) {
34309 start_pos = len + start_pos;
34310 }
34311 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34312
34313 /* combines steps 3, 6; step 7 is not needed */
34314 if (duk_is_undefined(ctx, 1)) {
34315 end_pos = len;
34316 } else {
34317 DUK_ASSERT(start_pos <= len);
34318 end_pos = start_pos + duk_to_int_clamped(ctx, 1, 0, len - start_pos);
34319 }
34320 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34321 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
34322 DUK_ASSERT(end_pos >= start_pos);
34323
34324 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
34325 return 1;
34326}
34327#else /* DUK_USE_SECTION_B */
34328DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
34329 DUK_UNREF(ctx);
34330 return DUK_RET_UNSUPPORTED_ERROR;
34331}
34332#endif /* DUK_USE_SECTION_B */
34333
34334DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
34335 duk_hstring *h;
34336 duk_int_t start_pos, end_pos;
34337 duk_int_t len;
34338
34339 h = duk_push_this_coercible_to_string(ctx);
34340 DUK_ASSERT(h != NULL);
34341 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
34342
34343 /* [ start end str ] */
34344
34345 start_pos = duk_to_int_clamped(ctx, 0, -len, len);
34346 if (start_pos < 0) {
34347 start_pos = len + start_pos;
34348 }
34349 if (duk_is_undefined(ctx, 1)) {
34350 end_pos = len;
34351 } else {
34352 end_pos = duk_to_int_clamped(ctx, 1, -len, len);
34353 if (end_pos < 0) {
34354 end_pos = len + end_pos;
34355 }
34356 }
34357 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34358 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
34359
34360 if (end_pos < start_pos) {
34361 end_pos = start_pos;
34362 }
34363
34364 DUK_ASSERT(end_pos >= start_pos);
34365
34366 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
34367 return 1;
34368}
34369
34370/*
34371 * Case conversion
34372 */
34373
34374DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) {
34375 duk_hthread *thr = (duk_hthread *) ctx;
34376 duk_small_int_t uppercase = duk_get_current_magic(ctx);
34377
34378 (void) duk_push_this_coercible_to_string(ctx);
34379 duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
34380 return 1;
34381}
34382
34383/*
34384 * indexOf() and lastIndexOf()
34385 */
34386
34387DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) {
34388 duk_hthread *thr = (duk_hthread *) ctx;
34389 duk_hstring *h_this;
34390 duk_hstring *h_search;
34391 duk_int_t clen_this;
34392 duk_int_t cpos;
34393 duk_int_t bpos;
34394 const duk_uint8_t *p_start, *p_end, *p;
34395 const duk_uint8_t *q_start;
34396 duk_int_t q_blen;
34397 duk_uint8_t firstbyte;
34398 duk_uint8_t t;
34399 duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */
34400
34401 h_this = duk_push_this_coercible_to_string(ctx);
34402 DUK_ASSERT(h_this != NULL);
34403 clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
34404
34405 h_search = duk_to_hstring(ctx, 0);
34406 DUK_ASSERT(h_search != NULL);
34407 q_start = DUK_HSTRING_GET_DATA(h_search);
34408 q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
34409
34410 duk_to_number(ctx, 1);
34411 if (duk_is_nan(ctx, 1) && is_lastindexof) {
34412 /* indexOf: NaN should cause pos to be zero.
34413 * lastIndexOf: NaN should cause pos to be +Infinity
34414 * (and later be clamped to len).
34415 */
34416 cpos = clen_this;
34417 } else {
34418 cpos = duk_to_int_clamped(ctx, 1, 0, clen_this);
34419 }
34420
34421 /* Empty searchstring always matches; cpos must be clamped here.
34422 * (If q_blen were < 0 due to clamped coercion, it would also be
34423 * caught here.)
34424 */
34425 if (q_blen <= 0) {
34426 duk_push_int(ctx, cpos);
34427 return 1;
34428 }
34429 DUK_ASSERT(q_blen > 0);
34430
34431 bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
34432
34433 p_start = DUK_HSTRING_GET_DATA(h_this);
34434 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
34435 p = p_start + bpos;
34436
34437 /* This loop is optimized for size. For speed, there should be
34438 * two separate loops, and we should ensure that memcmp() can be
34439 * used without an extra "will searchstring fit" check. Doing
34440 * the preconditioning for 'p' and 'p_end' is easy but cpos
34441 * must be updated if 'p' is wound back (backward scanning).
34442 */
34443
34444 firstbyte = q_start[0]; /* leading byte of match string */
34445 while (p <= p_end && p >= p_start) {
34446 t = *p;
34447
34448 /* For Ecmascript strings, this check can only match for
34449 * initial UTF-8 bytes (not continuation bytes). For other
34450 * strings all bets are off.
34451 */
34452
34453 if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
34454 DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
34455 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
34456 duk_push_int(ctx, cpos);
34457 return 1;
34458 }
34459 }
34460
34461 /* track cpos while scanning */
34462 if (is_lastindexof) {
34463 /* when going backwards, we decrement cpos 'early';
34464 * 'p' may point to a continuation byte of the char
34465 * at offset 'cpos', but that's OK because we'll
34466 * backtrack all the way to the initial byte.
34467 */
34468 if ((t & 0xc0) != 0x80) {
34469 cpos--;
34470 }
34471 p--;
34472 } else {
34473 if ((t & 0xc0) != 0x80) {
34474 cpos++;
34475 }
34476 p++;
34477 }
34478 }
34479
34480 /* Not found. Empty string case is handled specially above. */
34481 duk_push_int(ctx, -1);
34482 return 1;
34483}
34484
34485/*
34486 * replace()
34487 */
34488
34489/* XXX: the current implementation works but is quite clunky; it compiles
34490 * to almost 1,4kB of x86 code so it needs to be simplified (better approach,
34491 * shared helpers, etc). Some ideas for refactoring:
34492 *
34493 * - a primitive to convert a string into a regexp matcher (reduces matching
34494 * code at the cost of making matching much slower)
34495 * - use replace() as a basic helper for match() and split(), which are both
34496 * much simpler
34497 * - API call to get_prop and to_boolean
34498 */
34499
34500DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
34501 duk_hthread *thr = (duk_hthread *) ctx;
34502 duk_hstring *h_input;
34503 duk_hstring *h_match;
34504 duk_hstring *h_search;
34505 duk_hobject *h_re;
34506 duk_bufwriter_ctx bw_alloc;
34507 duk_bufwriter_ctx *bw;
34508#ifdef DUK_USE_REGEXP_SUPPORT
34509 duk_bool_t is_regexp;
34510 duk_bool_t is_global;
34511#endif
34512 duk_bool_t is_repl_func;
34513 duk_uint32_t match_start_coff, match_start_boff;
34514#ifdef DUK_USE_REGEXP_SUPPORT
34515 duk_int_t match_caps;
34516#endif
34517 duk_uint32_t prev_match_end_boff;
34518 const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */
34519 duk_size_t tmp_sz;
34520
34521 DUK_ASSERT_TOP(ctx, 2);
34522 h_input = duk_push_this_coercible_to_string(ctx);
34523 DUK_ASSERT(h_input != NULL);
34524
34525 bw = &bw_alloc;
34526 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */
34527
34528 DUK_ASSERT_TOP(ctx, 4);
34529
34530 /* stack[0] = search value
34531 * stack[1] = replace value
34532 * stack[2] = input string
34533 * stack[3] = result buffer
34534 */
34535
34536 h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
34537 if (h_re) {
34538#ifdef DUK_USE_REGEXP_SUPPORT
34539 is_regexp = 1;
34540 is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
34541
34542 if (is_global) {
34543 /* start match from beginning */
34544 duk_push_int(ctx, 0);
34545 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34546 }
34547#else /* DUK_USE_REGEXP_SUPPORT */
34548 return DUK_RET_UNSUPPORTED_ERROR;
34549#endif /* DUK_USE_REGEXP_SUPPORT */
34550 } else {
34551 duk_to_string(ctx, 0);
34552#ifdef DUK_USE_REGEXP_SUPPORT
34553 is_regexp = 0;
34554 is_global = 0;
34555#endif
34556 }
34557
34558 if (duk_is_function(ctx, 1)) {
34559 is_repl_func = 1;
34560 r_start = NULL;
34561 r_end = NULL;
34562 } else {
34563 duk_hstring *h_repl;
34564
34565 is_repl_func = 0;
34566 h_repl = duk_to_hstring(ctx, 1);
34567 DUK_ASSERT(h_repl != NULL);
34568 r_start = DUK_HSTRING_GET_DATA(h_repl);
34569 r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
34570 }
34571
34572 prev_match_end_boff = 0;
34573
34574 for (;;) {
34575 /*
34576 * If matching with a regexp:
34577 * - non-global RegExp: lastIndex not touched on a match, zeroed
34578 * on a non-match
34579 * - global RegExp: on match, lastIndex will be updated by regexp
34580 * executor to point to next char after the matching part (so that
34581 * characters in the matching part are not matched again)
34582 *
34583 * If matching with a string:
34584 * - always non-global match, find first occurrence
34585 *
34586 * We need:
34587 * - The character offset of start-of-match for the replacer function
34588 * - The byte offsets for start-of-match and end-of-match to implement
34589 * the replacement values $&, $`, and $', and to copy non-matching
34590 * input string portions (including header and trailer) verbatim.
34591 *
34592 * NOTE: the E5.1 specification is a bit vague how the RegExp should
34593 * behave in the replacement process; e.g. is matching done first for
34594 * all matches (in the global RegExp case) before any replacer calls
34595 * are made? See: test-bi-string-proto-replace.js for discussion.
34596 */
34597
34598 DUK_ASSERT_TOP(ctx, 4);
34599
34600#ifdef DUK_USE_REGEXP_SUPPORT
34601 if (is_regexp) {
34602 duk_dup(ctx, 0);
34603 duk_dup(ctx, 2);
34604 duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */
34605 if (!duk_is_object(ctx, -1)) {
34606 duk_pop(ctx);
34607 break;
34608 }
34609
34610 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
34611 DUK_ASSERT(duk_is_number(ctx, -1));
34612 match_start_coff = duk_get_int(ctx, -1);
34613 duk_pop(ctx);
34614
34615 duk_get_prop_index(ctx, -1, 0);
34616 DUK_ASSERT(duk_is_string(ctx, -1));
34617 h_match = duk_get_hstring(ctx, -1);
34618 DUK_ASSERT(h_match != NULL);
34619 duk_pop(ctx); /* h_match is borrowed, remains reachable through match_obj */
34620
34621 if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
34622 /* This should be equivalent to match() algorithm step 8.f.iii.2:
34623 * detect an empty match and allow it, but don't allow it twice.
34624 */
34625 duk_uint32_t last_index;
34626
34627 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34628 last_index = (duk_uint32_t) duk_get_uint(ctx, -1);
34629 DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
34630 (long) last_index, (long) (last_index + 1)));
34631 duk_pop(ctx);
34632 duk_push_int(ctx, last_index + 1);
34633 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34634 }
34635
34636 DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX); /* string limits */
34637 match_caps = (duk_int_t) duk_get_length(ctx, -1);
34638 } else {
34639#else /* DUK_USE_REGEXP_SUPPORT */
34640 { /* unconditionally */
34641#endif /* DUK_USE_REGEXP_SUPPORT */
34642 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
34643 const duk_uint8_t *q_start; /* match string */
34644 duk_size_t q_blen;
34645
34646#ifdef DUK_USE_REGEXP_SUPPORT
34647 DUK_ASSERT(!is_global); /* single match always */
34648#endif
34649
34650 p_start = DUK_HSTRING_GET_DATA(h_input);
34651 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
34652 p = p_start;
34653
34654 h_search = duk_get_hstring(ctx, 0);
34655 DUK_ASSERT(h_search != NULL);
34656 q_start = DUK_HSTRING_GET_DATA(h_search);
34657 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
34658
34659 p_end -= q_blen; /* ensure full memcmp() fits in while */
34660
34661 match_start_coff = 0;
34662
34663 while (p <= p_end) {
34664 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
34665 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
34666 duk_dup(ctx, 0);
34667 h_match = duk_get_hstring(ctx, -1);
34668 DUK_ASSERT(h_match != NULL);
34669#ifdef DUK_USE_REGEXP_SUPPORT
34670 match_caps = 0;
34671#endif
34672 goto found;
34673 }
34674
34675 /* track utf-8 non-continuation bytes */
34676 if ((p[0] & 0xc0) != 0x80) {
34677 match_start_coff++;
34678 }
34679 p++;
34680 }
34681
34682 /* not found */
34683 break;
34684 }
34685 found:
34686
34687 /* stack[0] = search value
34688 * stack[1] = replace value
34689 * stack[2] = input string
34690 * stack[3] = result buffer
34691 * stack[4] = regexp match OR match string
34692 */
34693
34694 match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
34695
34696 tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
34697 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
34698
34699 prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);
34700
34701 if (is_repl_func) {
34702 duk_idx_t idx_args;
34703 duk_hstring *h_repl;
34704
34705 /* regexp res_obj is at index 4 */
34706
34707 duk_dup(ctx, 1);
34708 idx_args = duk_get_top(ctx);
34709
34710#ifdef DUK_USE_REGEXP_SUPPORT
34711 if (is_regexp) {
34712 duk_int_t idx;
34713 duk_require_stack(ctx, match_caps + 2);
34714 for (idx = 0; idx < match_caps; idx++) {
34715 /* match followed by capture(s) */
34716 duk_get_prop_index(ctx, 4, idx);
34717 }
34718 } else {
34719#else /* DUK_USE_REGEXP_SUPPORT */
34720 { /* unconditionally */
34721#endif /* DUK_USE_REGEXP_SUPPORT */
34722 /* match == search string, by definition */
34723 duk_dup(ctx, 0);
34724 }
34725 duk_push_int(ctx, match_start_coff);
34726 duk_dup(ctx, 2);
34727
34728 /* [ ... replacer match [captures] match_char_offset input ] */
34729
34730 duk_call(ctx, duk_get_top(ctx) - idx_args);
34731 h_repl = duk_to_hstring(ctx, -1); /* -> [ ... repl_value ] */
34732 DUK_ASSERT(h_repl != NULL);
34733
34734 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
34735
34736 duk_pop(ctx); /* repl_value */
34737 } else {
34738 r = r_start;
34739
34740 while (r < r_end) {
34741 duk_int_t ch1;
34742 duk_int_t ch2;
34743#ifdef DUK_USE_REGEXP_SUPPORT
34744 duk_int_t ch3;
34745#endif
34746 duk_size_t left;
34747
34748 ch1 = *r++;
34749 if (ch1 != DUK_ASC_DOLLAR) {
34750 goto repl_write;
34751 }
34752 left = r_end - r;
34753
34754 if (left <= 0) {
34755 goto repl_write;
34756 }
34757
34758 ch2 = r[0];
34759 switch ((int) ch2) {
34760 case DUK_ASC_DOLLAR: {
34761 ch1 = (1 << 8) + DUK_ASC_DOLLAR;
34762 goto repl_write;
34763 }
34764 case DUK_ASC_AMP: {
34765 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match);
34766 r++;
34767 continue;
34768 }
34769 case DUK_ASC_GRAVE: {
34770 tmp_sz = (duk_size_t) match_start_boff;
34771 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz);
34772 r++;
34773 continue;
34774 }
34775 case DUK_ASC_SINGLEQUOTE: {
34776 duk_uint32_t match_end_boff;
34777
34778 /* Use match charlen instead of bytelen, just in case the input and
34779 * match codepoint encodings would have different lengths.
34780 */
34781 match_end_boff = duk_heap_strcache_offset_char2byte(thr,
34782 h_input,
34783 match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match));
34784
34785 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
34786 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
34787 r++;
34788 continue;
34789 }
34790 default: {
34791#ifdef DUK_USE_REGEXP_SUPPORT
34792 duk_int_t capnum, captmp, capadv;
34793 /* XXX: optional check, match_caps is zero if no regexp,
34794 * so dollar will be interpreted literally anyway.
34795 */
34796
34797 if (!is_regexp) {
34798 goto repl_write;
34799 }
34800
34801 if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) {
34802 goto repl_write;
34803 }
34804 capnum = ch2 - DUK_ASC_0;
34805 capadv = 1;
34806
34807 if (left >= 2) {
34808 ch3 = r[1];
34809 if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) {
34810 captmp = capnum * 10 + (ch3 - DUK_ASC_0);
34811 if (captmp < match_caps) {
34812 capnum = captmp;
34813 capadv = 2;
34814 }
34815 }
34816 }
34817
34818 if (capnum > 0 && capnum < match_caps) {
34819 DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */
34820
34821 /* regexp res_obj is at offset 4 */
34822 duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum);
34823 if (duk_is_string(ctx, -1)) {
34824 duk_hstring *h_tmp_str;
34825
34826 h_tmp_str = duk_get_hstring(ctx, -1);
34827 DUK_ASSERT(h_tmp_str != NULL);
34828
34829 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
34830 } else {
34831 /* undefined -> skip (replaced with empty) */
34832 }
34833 duk_pop(ctx);
34834 r += capadv;
34835 continue;
34836 } else {
34837 goto repl_write;
34838 }
34839#else /* DUK_USE_REGEXP_SUPPORT */
34840 goto repl_write; /* unconditionally */
34841#endif /* DUK_USE_REGEXP_SUPPORT */
34842 } /* default case */
34843 } /* switch (ch2) */
34844
34845 repl_write:
34846 /* ch1 = (r_increment << 8) + byte */
34847
34848 DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff));
34849 r += ch1 >> 8;
34850 } /* while repl */
34851 } /* if (is_repl_func) */
34852
34853 duk_pop(ctx); /* pop regexp res_obj or match string */
34854
34855#ifdef DUK_USE_REGEXP_SUPPORT
34856 if (!is_global) {
34857#else
34858 { /* unconditionally; is_global==0 */
34859#endif
34860 break;
34861 }
34862 }
34863
34864 /* trailer */
34865 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
34866 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
34867
34868 DUK_ASSERT_TOP(ctx, 4);
34869 DUK_BW_COMPACT(thr, bw);
34870 duk_to_string(ctx, -1);
34871 return 1;
34872}
34873
34874/*
34875 * split()
34876 */
34877
34878/* XXX: very messy now, but works; clean up, remove unused variables (nomimally
34879 * used so compiler doesn't complain).
34880 */
34881
34882DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
34883 duk_hthread *thr = (duk_hthread *) ctx;
34884 duk_hstring *h_input;
34885 duk_hstring *h_sep;
34886 duk_uint32_t limit;
34887 duk_uint32_t arr_idx;
34888#ifdef DUK_USE_REGEXP_SUPPORT
34889 duk_bool_t is_regexp;
34890#endif
34891 duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */
34892 duk_uint32_t prev_match_end_coff, prev_match_end_boff;
34893 duk_uint32_t match_start_boff, match_start_coff;
34894 duk_uint32_t match_end_boff, match_end_coff;
34895
34896 DUK_UNREF(thr);
34897
34898 h_input = duk_push_this_coercible_to_string(ctx);
34899 DUK_ASSERT(h_input != NULL);
34900
34901 duk_push_array(ctx);
34902
34903 if (duk_is_undefined(ctx, 1)) {
34904 limit = 0xffffffffUL;
34905 } else {
34906 limit = duk_to_uint32(ctx, 1);
34907 }
34908
34909 if (limit == 0) {
34910 return 1;
34911 }
34912
34913 /* If the separator is a RegExp, make a "clone" of it. The specification
34914 * algorithm calls [[Match]] directly for specific indices; we emulate this
34915 * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
34916 * which will use global-style matching even when the RegExp itself is non-global.
34917 */
34918
34919 if (duk_is_undefined(ctx, 0)) {
34920 /* The spec algorithm first does "R = ToString(separator)" before checking
34921 * whether separator is undefined. Since this is side effect free, we can
34922 * skip the ToString() here.
34923 */
34924 duk_dup(ctx, 2);
34925 duk_put_prop_index(ctx, 3, 0);
34926 return 1;
34927 } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
34928#ifdef DUK_USE_REGEXP_SUPPORT
34929 duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
34930 duk_dup(ctx, 0);
34931 duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
34932 duk_replace(ctx, 0);
34933 /* lastIndex is initialized to zero by new RegExp() */
34934 is_regexp = 1;
34935#else
34936 return DUK_RET_UNSUPPORTED_ERROR;
34937#endif
34938 } else {
34939 duk_to_string(ctx, 0);
34940#ifdef DUK_USE_REGEXP_SUPPORT
34941 is_regexp = 0;
34942#endif
34943 }
34944
34945 /* stack[0] = separator (string or regexp)
34946 * stack[1] = limit
34947 * stack[2] = input string
34948 * stack[3] = result array
34949 */
34950
34951 prev_match_end_boff = 0;
34952 prev_match_end_coff = 0;
34953 arr_idx = 0;
34954 matched = 0;
34955
34956 for (;;) {
34957 /*
34958 * The specification uses RegExp [[Match]] to attempt match at specific
34959 * offsets. We don't have such a primitive, so we use an actual RegExp
34960 * and tweak lastIndex. Since the RegExp may be non-global, we use a
34961 * special variant which forces global-like behavior for matching.
34962 */
34963
34964 DUK_ASSERT_TOP(ctx, 4);
34965
34966#ifdef DUK_USE_REGEXP_SUPPORT
34967 if (is_regexp) {
34968 duk_dup(ctx, 0);
34969 duk_dup(ctx, 2);
34970 duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */
34971 if (!duk_is_object(ctx, -1)) {
34972 duk_pop(ctx);
34973 break;
34974 }
34975 matched = 1;
34976
34977 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
34978 DUK_ASSERT(duk_is_number(ctx, -1));
34979 match_start_coff = duk_get_int(ctx, -1);
34980 match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
34981 duk_pop(ctx);
34982
34983 if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
34984 /* don't allow an empty match at the end of the string */
34985 duk_pop(ctx);
34986 break;
34987 }
34988
34989 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34990 DUK_ASSERT(duk_is_number(ctx, -1));
34991 match_end_coff = duk_get_int(ctx, -1);
34992 match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
34993 duk_pop(ctx);
34994
34995 /* empty match -> bump and continue */
34996 if (prev_match_end_boff == match_end_boff) {
34997 duk_push_int(ctx, match_end_coff + 1);
34998 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34999 duk_pop(ctx);
35000 continue;
35001 }
35002 } else {
35003#else /* DUK_USE_REGEXP_SUPPORT */
35004 { /* unconditionally */
35005#endif /* DUK_USE_REGEXP_SUPPORT */
35006 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
35007 const duk_uint8_t *q_start; /* match string */
35008 duk_size_t q_blen, q_clen;
35009
35010 p_start = DUK_HSTRING_GET_DATA(h_input);
35011 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
35012 p = p_start + prev_match_end_boff;
35013
35014 h_sep = duk_get_hstring(ctx, 0);
35015 DUK_ASSERT(h_sep != NULL);
35016 q_start = DUK_HSTRING_GET_DATA(h_sep);
35017 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
35018 q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
35019
35020 p_end -= q_blen; /* ensure full memcmp() fits in while */
35021
35022 match_start_coff = prev_match_end_coff;
35023
35024 if (q_blen == 0) {
35025 /* Handle empty separator case: it will always match, and always
35026 * triggers the check in step 13.c.iii initially. Note that we
35027 * must skip to either end of string or start of first codepoint,
35028 * skipping over any continuation bytes!
35029 *
35030 * Don't allow an empty string to match at the end of the input.
35031 */
35032
35033 matched = 1; /* empty separator can always match */
35034
35035 match_start_coff++;
35036 p++;
35037 while (p < p_end) {
35038 if ((p[0] & 0xc0) != 0x80) {
35039 goto found;
35040 }
35041 p++;
35042 }
35043 goto not_found;
35044 }
35045
35046 DUK_ASSERT(q_blen > 0 && q_clen > 0);
35047 while (p <= p_end) {
35048 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
35049 DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */
35050 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
35051 /* never an empty match, so step 13.c.iii can't be triggered */
35052 goto found;
35053 }
35054
35055 /* track utf-8 non-continuation bytes */
35056 if ((p[0] & 0xc0) != 0x80) {
35057 match_start_coff++;
35058 }
35059 p++;
35060 }
35061
35062 not_found:
35063 /* not found */
35064 break;
35065
35066 found:
35067 matched = 1;
35068 match_start_boff = (duk_uint32_t) (p - p_start);
35069 match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */
35070 match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */
35071
35072 /* empty match (may happen with empty separator) -> bump and continue */
35073 if (prev_match_end_boff == match_end_boff) {
35074 prev_match_end_boff++;
35075 prev_match_end_coff++;
35076 continue;
35077 }
35078 } /* if (is_regexp) */
35079
35080 /* stack[0] = separator (string or regexp)
35081 * stack[1] = limit
35082 * stack[2] = input string
35083 * stack[3] = result array
35084 * stack[4] = regexp res_obj (if is_regexp)
35085 */
35086
35087 DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld",
35088 (long) match_start_boff, (long) match_start_coff,
35089 (long) match_end_boff, (long) match_end_coff,
35090 (long) prev_match_end_boff, (long) prev_match_end_coff));
35091
35092 duk_push_lstring(ctx,
35093 (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
35094 (duk_size_t) (match_start_boff - prev_match_end_boff));
35095 duk_put_prop_index(ctx, 3, arr_idx);
35096 arr_idx++;
35097 if (arr_idx >= limit) {
35098 goto hit_limit;
35099 }
35100
35101#ifdef DUK_USE_REGEXP_SUPPORT
35102 if (is_regexp) {
35103 duk_size_t i, len;
35104
35105 len = duk_get_length(ctx, 4);
35106 for (i = 1; i < len; i++) {
35107 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */
35108 duk_get_prop_index(ctx, 4, (duk_uarridx_t) i);
35109 duk_put_prop_index(ctx, 3, arr_idx);
35110 arr_idx++;
35111 if (arr_idx >= limit) {
35112 goto hit_limit;
35113 }
35114 }
35115
35116 duk_pop(ctx);
35117 /* lastIndex already set up for next match */
35118 } else {
35119#else /* DUK_USE_REGEXP_SUPPORT */
35120 { /* unconditionally */
35121#endif /* DUK_USE_REGEXP_SUPPORT */
35122 /* no action */
35123 }
35124
35125 prev_match_end_boff = match_end_boff;
35126 prev_match_end_coff = match_end_coff;
35127 continue;
35128 } /* for */
35129
35130 /* Combined step 11 (empty string special case) and 14-15. */
35131
35132 DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
35133 (long) prev_match_end_boff, (long) prev_match_end_coff));
35134
35135 if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) {
35136 /* Add trailer if:
35137 * a) non-empty input
35138 * b) empty input and no (zero size) match found (step 11)
35139 */
35140
35141 duk_push_lstring(ctx,
35142 (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
35143 (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
35144 duk_put_prop_index(ctx, 3, arr_idx);
35145 /* No arr_idx update or limit check */
35146 }
35147
35148 return 1;
35149
35150 hit_limit:
35151#ifdef DUK_USE_REGEXP_SUPPORT
35152 if (is_regexp) {
35153 duk_pop(ctx);
35154 }
35155#endif
35156
35157 return 1;
35158}
35159
35160/*
35161 * Various
35162 */
35163
35164#ifdef DUK_USE_REGEXP_SUPPORT
35165DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t index, duk_bool_t force_new) {
35166 duk_hobject *h;
35167
35168 /* Shared helper for match() steps 3-4, search() steps 3-4. */
35169
35170 DUK_ASSERT(index >= 0);
35171
35172 if (force_new) {
35173 goto do_new;
35174 }
35175
35176 h = duk_get_hobject_with_class(ctx, index, DUK_HOBJECT_CLASS_REGEXP);
35177 if (!h) {
35178 goto do_new;
35179 }
35180 return;
35181
35182 do_new:
35183 duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
35184 duk_dup(ctx, index);
35185 duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
35186 duk_replace(ctx, index);
35187}
35188#endif /* DUK_USE_REGEXP_SUPPORT */
35189
35190#ifdef DUK_USE_REGEXP_SUPPORT
35191DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
35192 duk_hthread *thr = (duk_hthread *) ctx;
35193
35194 /* Easiest way to implement the search required by the specification
35195 * is to do a RegExp test() with lastIndex forced to zero. To avoid
35196 * side effects on the argument, "clone" the RegExp if a RegExp was
35197 * given as input.
35198 *
35199 * The global flag of the RegExp should be ignored; setting lastIndex
35200 * to zero (which happens when "cloning" the RegExp) should have an
35201 * equivalent effect.
35202 */
35203
35204 DUK_ASSERT_TOP(ctx, 1);
35205 (void) duk_push_this_coercible_to_string(ctx); /* at index 1 */
35206 duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);
35207
35208 /* stack[0] = regexp
35209 * stack[1] = string
35210 */
35211
35212 /* Avoid using RegExp.prototype methods, as they're writable and
35213 * configurable and may have been changed.
35214 */
35215
35216 duk_dup(ctx, 0);
35217 duk_dup(ctx, 1); /* [ ... re_obj input ] */
35218 duk_regexp_match(thr); /* -> [ ... res_obj ] */
35219
35220 if (!duk_is_object(ctx, -1)) {
35221 duk_push_int(ctx, -1);
35222 return 1;
35223 }
35224
35225 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
35226 DUK_ASSERT(duk_is_number(ctx, -1));
35227 return 1;
35228}
35229#else /* DUK_USE_REGEXP_SUPPORT */
35230DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
35231 DUK_UNREF(ctx);
35232 return DUK_RET_UNSUPPORTED_ERROR;
35233}
35234#endif /* DUK_USE_REGEXP_SUPPORT */
35235
35236#ifdef DUK_USE_REGEXP_SUPPORT
35237DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
35238 duk_hthread *thr = (duk_hthread *) ctx;
35239 duk_bool_t global;
35240 duk_int_t prev_last_index;
35241 duk_int_t this_index;
35242 duk_int_t arr_idx;
35243
35244 DUK_ASSERT_TOP(ctx, 1);
35245 (void) duk_push_this_coercible_to_string(ctx);
35246 duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/);
35247 global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
35248 DUK_ASSERT_TOP(ctx, 2);
35249
35250 /* stack[0] = regexp
35251 * stack[1] = string
35252 */
35253
35254 if (!global) {
35255 duk_regexp_match(thr); /* -> [ res_obj ] */
35256 return 1; /* return 'res_obj' */
35257 }
35258
35259 /* Global case is more complex. */
35260
35261 /* [ regexp string ] */
35262
35263 duk_push_int(ctx, 0);
35264 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
35265 duk_push_array(ctx);
35266
35267 /* [ regexp string res_arr ] */
35268
35269 prev_last_index = 0;
35270 arr_idx = 0;
35271
35272 for (;;) {
35273 DUK_ASSERT_TOP(ctx, 3);
35274
35275 duk_dup(ctx, 0);
35276 duk_dup(ctx, 1);
35277 duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */
35278
35279 if (!duk_is_object(ctx, -1)) {
35280 duk_pop(ctx);
35281 break;
35282 }
35283
35284 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
35285 DUK_ASSERT(duk_is_number(ctx, -1));
35286 this_index = duk_get_int(ctx, -1);
35287 duk_pop(ctx);
35288
35289 if (this_index == prev_last_index) {
35290 this_index++;
35291 duk_push_int(ctx, this_index);
35292 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
35293 }
35294 prev_last_index = this_index;
35295
35296 duk_get_prop_index(ctx, -1, 0); /* match string */
35297 duk_put_prop_index(ctx, 2, arr_idx);
35298 arr_idx++;
35299 duk_pop(ctx); /* res_obj */
35300 }
35301
35302 if (arr_idx == 0) {
35303 duk_push_null(ctx);
35304 }
35305
35306 return 1; /* return 'res_arr' or 'null' */
35307}
35308#else /* DUK_USE_REGEXP_SUPPORT */
35309DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
35310 DUK_UNREF(ctx);
35311 return DUK_RET_UNSUPPORTED_ERROR;
35312}
35313#endif /* DUK_USE_REGEXP_SUPPORT */
35314
35315DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) {
35316 /* duk_concat() coerces arguments with ToString() in correct order */
35317 (void) duk_push_this_coercible_to_string(ctx);
35318 duk_insert(ctx, 0); /* this is relatively expensive */
35319 duk_concat(ctx, duk_get_top(ctx));
35320 return 1;
35321}
35322
35323DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx) {
35324 DUK_ASSERT_TOP(ctx, 0);
35325 (void) duk_push_this_coercible_to_string(ctx);
35326 duk_trim(ctx, 0);
35327 DUK_ASSERT_TOP(ctx, 1);
35328 return 1;
35329}
35330
35331DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) {
35332 duk_hstring *h1;
35333 duk_hstring *h2;
35334 duk_size_t h1_len, h2_len, prefix_len;
35335 duk_small_int_t ret = 0;
35336 duk_small_int_t rc;
35337
35338 /* The current implementation of localeCompare() is simply a codepoint
35339 * by codepoint comparison, implemented with a simple string compare
35340 * because UTF-8 should preserve codepoint ordering (assuming valid
35341 * shortest UTF-8 encoding).
35342 *
35343 * The specification requires that the return value must be related
35344 * to the sort order: e.g. negative means that 'this' comes before
35345 * 'that' in sort order. We assume an ascending sort order.
35346 */
35347
35348 /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
35349
35350 h1 = duk_push_this_coercible_to_string(ctx);
35351 DUK_ASSERT(h1 != NULL);
35352
35353 h2 = duk_to_hstring(ctx, 0);
35354 DUK_ASSERT(h2 != NULL);
35355
35356 h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
35357 h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
35358 prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
35359
35360 /* Zero size compare not an issue with DUK_MEMCMP. */
35361 rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1),
35362 (const void *) DUK_HSTRING_GET_DATA(h2),
35363 (size_t) prefix_len);
35364
35365 if (rc < 0) {
35366 ret = -1;
35367 goto done;
35368 } else if (rc > 0) {
35369 ret = 1;
35370 goto done;
35371 }
35372
35373 /* prefix matches, lengths matter now */
35374 if (h1_len > h2_len) {
35375 ret = 1;
35376 goto done;
35377 } else if (h1_len == h2_len) {
35378 DUK_ASSERT(ret == 0);
35379 goto done;
35380 }
35381 ret = -1;
35382 goto done;
35383
35384 done:
35385 duk_push_int(ctx, (duk_int_t) ret);
35386 return 1;
35387}
35388#line 1 "duk_bi_thread.c"
35389/*
35390 * Thread builtins
35391 */
35392
35393/* include removed: duk_internal.h */
35394
35395/*
35396 * Constructor
35397 */
35398
35399DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
35400 duk_hthread *new_thr;
35401 duk_hobject *func;
35402
35403 /* XXX: need a duk_require_func_or_lfunc_coerce() */
35404 if (!duk_is_callable(ctx, 0)) {
35405 return DUK_RET_TYPE_ERROR;
35406 }
35407 func = duk_require_hobject_or_lfunc_coerce(ctx, 0);
35408 DUK_ASSERT(func != NULL);
35409
35410 duk_push_thread(ctx);
35411 new_thr = (duk_hthread *) duk_get_hobject(ctx, -1);
35412 DUK_ASSERT(new_thr != NULL);
35413 new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
35414
35415 /* push initial function call to new thread stack; this is
35416 * picked up by resume().
35417 */
35418 duk_push_hobject((duk_context *) new_thr, func);
35419
35420 return 1; /* return thread */
35421}
35422
35423/*
35424 * Resume a thread.
35425 *
35426 * The thread must be in resumable state, either (a) new thread which hasn't
35427 * yet started, or (b) a thread which has previously yielded. This method
35428 * must be called from an Ecmascript function.
35429 *
35430 * Args:
35431 * - thread
35432 * - value
35433 * - isError (defaults to false)
35434 *
35435 * Note: yield and resume handling is currently asymmetric.
35436 */
35437
35438DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
35439 duk_hthread *thr = (duk_hthread *) ctx;
35440 duk_hthread *thr_resume;
35441 duk_tval *tv;
35442 duk_hobject *func;
35443 duk_hobject *caller_func;
35444 duk_small_int_t is_error;
35445
35446 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
35447 (duk_tval *) duk_get_tval(ctx, 0),
35448 (duk_tval *) duk_get_tval(ctx, 1),
35449 (duk_tval *) duk_get_tval(ctx, 2)));
35450
35451 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
35452 DUK_ASSERT(thr->heap->curr_thread == thr);
35453
35454 thr_resume = duk_require_hthread(ctx, 0);
35455 is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
35456 duk_set_top(ctx, 2);
35457
35458 /* [ thread value ] */
35459
35460 /*
35461 * Thread state and calling context checks
35462 */
35463
35464 if (thr->callstack_top < 2) {
35465 DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
35466 goto state_error;
35467 }
35468 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
35469 DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
35470 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
35471
35472 caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
35473 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
35474 DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
35475 goto state_error;
35476 }
35477
35478 /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
35479 * like for yield.
35480 */
35481
35482 if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
35483 thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
35484 DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
35485 goto state_error;
35486 }
35487
35488 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
35489 thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
35490
35491 /* Further state-dependent pre-checks */
35492
35493 if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
35494 /* no pre-checks now, assume a previous yield() has left things in
35495 * tip-top shape (longjmp handler will assert for these).
35496 */
35497 } else {
35498 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
35499
35500 if ((thr_resume->callstack_top != 0) ||
35501 (thr_resume->valstack_top - thr_resume->valstack != 1)) {
35502 goto state_invalid_initial;
35503 }
35504 tv = &thr_resume->valstack_top[-1];
35505 DUK_ASSERT(tv >= thr_resume->valstack && tv < thr_resume->valstack_top);
35506 if (!DUK_TVAL_IS_OBJECT(tv)) {
35507 goto state_invalid_initial;
35508 }
35509 func = DUK_TVAL_GET_OBJECT(tv);
35510 DUK_ASSERT(func != NULL);
35511 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
35512 /* Note: cannot be a bound function either right now,
35513 * this would be easy to relax though.
35514 */
35515 goto state_invalid_initial;
35516 }
35517
35518 }
35519
35520 /*
35521 * The error object has been augmented with a traceback and other
35522 * info from its creation point -- usually another thread. The
35523 * error handler is called here right before throwing, but it also
35524 * runs in the resumer's thread. It might be nice to get a traceback
35525 * from the resumee but this is not the case now.
35526 */
35527
35528#if defined(DUK_USE_AUGMENT_ERROR_THROW)
35529 if (is_error) {
35530 DUK_ASSERT_TOP(ctx, 2); /* value (error) is at stack top */
35531 duk_err_augment_error_throw(thr); /* in resumer's context */
35532 }
35533#endif
35534
35535#ifdef DUK_USE_DEBUG
35536 if (is_error) {
35537 DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
35538 (duk_tval *) duk_get_tval(ctx, 0),
35539 (duk_tval *) duk_get_tval(ctx, 1)));
35540 } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
35541 DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
35542 (duk_tval *) duk_get_tval(ctx, 0),
35543 (duk_tval *) duk_get_tval(ctx, 1)));
35544 } else {
35545 DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
35546 (duk_tval *) duk_get_tval(ctx, 0),
35547 (duk_tval *) duk_get_tval(ctx, 1)));
35548 }
35549#endif
35550
35551 thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
35552
35553 /* lj value2: thread */
35554 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
35555 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */
35556
35557 /* lj value1: value */
35558 DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
35559 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
35560 DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
35561
35562 thr->heap->lj.iserror = is_error;
35563
35564 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
35565 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
35566 return 0; /* never here */
35567
35568 state_invalid_initial:
35569 DUK_ERROR_TYPE(thr, "invalid initial thread state/stack");
35570 return 0; /* never here */
35571
35572 state_error:
35573 DUK_ERROR_TYPE(thr, "invalid state");
35574 return 0; /* never here */
35575}
35576
35577/*
35578 * Yield the current thread.
35579 *
35580 * The thread must be in yieldable state: it must have a resumer, and there
35581 * must not be any yield-preventing calls (native calls and constructor calls,
35582 * currently) in the thread's call stack (otherwise a resume would not be
35583 * possible later). This method must be called from an Ecmascript function.
35584 *
35585 * Args:
35586 * - value
35587 * - isError (defaults to false)
35588 *
35589 * Note: yield and resume handling is currently asymmetric.
35590 */
35591
35592DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
35593 duk_hthread *thr = (duk_hthread *) ctx;
35594 duk_hobject *caller_func;
35595 duk_small_int_t is_error;
35596
35597 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
35598 (duk_tval *) duk_get_tval(ctx, 0),
35599 (duk_tval *) duk_get_tval(ctx, 1)));
35600
35601 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
35602 DUK_ASSERT(thr->heap->curr_thread == thr);
35603
35604 is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
35605 duk_set_top(ctx, 1);
35606
35607 /* [ value ] */
35608
35609 /*
35610 * Thread state and calling context checks
35611 */
35612
35613 if (!thr->resumer) {
35614 DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
35615 goto state_error;
35616 }
35617 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
35618
35619 if (thr->callstack_top < 2) {
35620 DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
35621 goto state_error;
35622 }
35623 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
35624 DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
35625 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
35626
35627 caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
35628 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
35629 DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
35630 goto state_error;
35631 }
35632
35633 DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
35634 if (thr->callstack_preventcount != 1) {
35635 /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
35636 DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
35637 (long) thr->callstack_preventcount));
35638 goto state_error;
35639 }
35640
35641 /*
35642 * The error object has been augmented with a traceback and other
35643 * info from its creation point -- usually the current thread.
35644 * The error handler, however, is called right before throwing
35645 * and runs in the yielder's thread.
35646 */
35647
35648#if defined(DUK_USE_AUGMENT_ERROR_THROW)
35649 if (is_error) {
35650 DUK_ASSERT_TOP(ctx, 1); /* value (error) is at stack top */
35651 duk_err_augment_error_throw(thr); /* in yielder's context */
35652 }
35653#endif
35654
35655#ifdef DUK_USE_DEBUG
35656 if (is_error) {
35657 DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
35658 (duk_tval *) duk_get_tval(ctx, 0)));
35659 } else {
35660 DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
35661 (duk_tval *) duk_get_tval(ctx, 0)));
35662 }
35663#endif
35664
35665 /*
35666 * Process yield
35667 *
35668 * After longjmp(), processing continues in bytecode executor longjmp
35669 * handler, which will e.g. update thr->resumer to NULL.
35670 */
35671
35672 thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
35673
35674 /* lj value1: value */
35675 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
35676 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
35677 DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
35678
35679 thr->heap->lj.iserror = is_error;
35680
35681 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
35682 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
35683 return 0; /* never here */
35684
35685 state_error:
35686 DUK_ERROR_TYPE(thr, "invalid state");
35687 return 0; /* never here */
35688}
35689
35690DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
35691 duk_push_current_thread(ctx);
35692 return 1;
35693}
35694#line 1 "duk_bi_thrower.c"
35695/*
35696 * Type error thrower, E5 Section 13.2.3.
35697 */
35698
35699/* include removed: duk_internal.h */
35700
35701DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) {
35702 DUK_UNREF(ctx);
35703 return DUK_RET_TYPE_ERROR;
35704}
35705#line 1 "duk_debug_fixedbuffer.c"
35706/*
35707 * Fixed buffer helper useful for debugging, requires no allocation
35708 * which is critical for debugging.
35709 */
35710
35711/* include removed: duk_internal.h */
35712
35713#ifdef DUK_USE_DEBUG
35714
35715DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
35716 duk_size_t avail;
35717 duk_size_t copylen;
35718
35719 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
35720 if (length > avail) {
35721 copylen = avail;
35722 fb->truncated = 1;
35723 } else {
35724 copylen = length;
35725 }
35726 DUK_MEMCPY(fb->buffer + fb->offset, buffer, copylen);
35727 fb->offset += copylen;
35728}
35729
35730DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
35731 duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
35732}
35733
35734DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
35735 duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
35736}
35737
35738DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
35739 duk_size_t avail;
35740 va_list ap;
35741
35742 va_start(ap, fmt);
35743 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
35744 if (avail > 0) {
35745 duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
35746 if (res < 0) {
35747 /* error */
35748 } else if ((duk_size_t) res >= avail) {
35749 /* (maybe) truncated */
35750 fb->offset += avail;
35751 if ((duk_size_t) res > avail) {
35752 /* actual chars dropped (not just NUL term) */
35753 fb->truncated = 1;
35754 }
35755 } else {
35756 /* normal */
35757 fb->offset += res;
35758 }
35759 }
35760 va_end(ap);
35761}
35762
35763DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) {
35764 char buf[64+1];
35765 duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size);
35766 buf[sizeof(buf) - 1] = (char) 0;
35767 duk_fb_put_cstring(fb, buf);
35768}
35769
35770DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
35771 return (fb->offset >= fb->length);
35772}
35773
35774#endif /* DUK_USE_DEBUG */
35775#line 1 "duk_debug_heap.c"
35776/*
35777 * Debug dumping of duk_heap.
35778 */
35779
35780/* include removed: duk_internal.h */
35781
35782#ifdef DUK_USE_DEBUG
35783
35784#if 0 /*unused*/
35785DUK_LOCAL void duk__sanitize_snippet(char *buf, duk_size_t buf_size, duk_hstring *str) {
35786 duk_size_t i;
35787 duk_size_t nchars;
35788 duk_size_t maxchars;
35789 duk_uint8_t *data;
35790
35791 DUK_MEMZERO(buf, buf_size);
35792
35793 maxchars = (duk_size_t) (buf_size - 1);
35794 data = DUK_HSTRING_GET_DATA(str);
35795 nchars = ((duk_size_t) str->blen < maxchars ? (duk_size_t) str->blen : maxchars);
35796 for (i = 0; i < nchars; i++) {
35797 duk_small_int_t c = (duk_small_int_t) data[i];
35798 if (c < 0x20 || c > 0x7e) {
35799 c = '.';
35800 }
35801 buf[i] = (char) c;
35802 }
35803}
35804#endif
35805
35806#if 0
35807DUK_LOCAL const char *duk__get_heap_type_string(duk_heaphdr *hdr) {
35808 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
35809 case DUK_HTYPE_STRING:
35810 return "string";
35811 case DUK_HTYPE_OBJECT:
35812 return "object";
35813 case DUK_HTYPE_BUFFER:
35814 return "buffer";
35815 default:
35816 return "???";
35817 }
35818}
35819#endif
35820
35821#if 0
35822DUK_LOCAL void duk__dump_indented(duk_heaphdr *obj, int index) {
35823 DUK_UNREF(obj);
35824 DUK_UNREF(index);
35825 DUK_UNREF(duk__get_heap_type_string);
35826
35827#ifdef DUK_USE_REFERENCE_COUNTING
35828 DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx, ref: %ld) -> %!O",
35829 (long) index,
35830 (void *) obj,
35831 (const char *) duk__get_heap_type_string(obj),
35832 (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
35833 (long) DUK_HEAPHDR_GET_REFCOUNT(obj),
35834 (duk_heaphdr *) obj));
35835#else
35836 DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx) -> %!O",
35837 (long) index,
35838 (void *) obj,
35839 (const char *) duk__get_heap_type_string(obj),
35840 (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
35841 (duk_heaphdr *) obj));
35842#endif
35843}
35844#endif
35845
35846#if 0 /*unused*/
35847DUK_LOCAL void duk__dump_heaphdr_list(duk_heap *heap, duk_heaphdr *root, const char *name) {
35848 duk_int_t count;
35849 duk_heaphdr *curr;
35850
35851 DUK_UNREF(heap);
35852 DUK_UNREF(name);
35853
35854 count = 0;
35855 curr = root;
35856 while (curr) {
35857 count++;
35858 curr = DUK_HEAPHDR_GET_NEXT(curr);
35859 }
35860
35861 DUK_D(DUK_DPRINT("%s, %ld objects", (const char *) name, (long) count));
35862
35863 count = 0;
35864 curr = root;
35865 while (curr) {
35866 count++;
35867 duk__dump_indented(curr, count);
35868 curr = DUK_HEAPHDR_GET_NEXT(curr);
35869 }
35870}
35871#endif
35872
35873#if 0 /*unused*/
35874DUK_LOCAL void duk__dump_stringtable(duk_heap *heap) {
35875 duk_uint_fast32_t i;
35876 char buf[64+1];
35877
35878 DUK_D(DUK_DPRINT("stringtable %p, used %ld, size %ld, load %ld%%",
35879 (void *) heap->strtable,
35880 (long) heap->st_used,
35881 (long) heap->st_size,
35882 (long) (((double) heap->st_used) / ((double) heap->st_size) * 100.0)));
35883
35884 for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
35885 duk_hstring *e = heap->strtable[i];
35886
35887 if (!e) {
35888 DUK_D(DUK_DPRINT(" [%ld]: NULL", (long) i));
35889 } else if (e == DUK_STRTAB_DELETED_MARKER(heap)) {
35890 DUK_D(DUK_DPRINT(" [%ld]: DELETED", (long) i));
35891 } else {
35892 duk__sanitize_snippet(buf, sizeof(buf), e);
35893
35894#ifdef DUK_USE_REFERENCE_COUNTING
35895 DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx, ref: %ld) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
35896 "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
35897 (long) i,
35898 (void *) e,
35899 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
35900 (long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) e),
35901 (const char *) buf,
35902 (unsigned long) e->hash,
35903 (long) e->blen,
35904 (long) e->clen,
35905 (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
35906 (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
35907 (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
35908 (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
35909 (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
35910#else
35911 DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
35912 "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
35913 (long) i,
35914 (void *) e,
35915 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
35916 (const char *) buf,
35917 (long) e->hash,
35918 (long) e->blen,
35919 (long) e->clen,
35920 (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
35921 (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
35922 (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
35923 (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
35924 (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
35925#endif
35926 }
35927 }
35928}
35929#endif
35930
35931#if 0 /*unused*/
35932DUK_LOCAL void duk__dump_strcache(duk_heap *heap) {
35933 duk_uint_fast32_t i;
35934 char buf[64+1];
35935
35936 DUK_D(DUK_DPRINT("stringcache"));
35937
35938 for (i = 0; i < (duk_uint_fast32_t) DUK_HEAP_STRCACHE_SIZE; i++) {
35939 duk_strcache *c = &heap->strcache[i];
35940 if (!c->h) {
35941 DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld, cidx=%ld, str=NULL",
35942 (long) i, (long) c->bidx, (long) c->cidx));
35943 } else {
35944 duk__sanitize_snippet(buf, sizeof(buf), c->h);
35945 DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld cidx=%ld str=%s",
35946 (long) i, (long) c->bidx, (long) c->cidx, (const char *) buf));
35947 }
35948 }
35949}
35950#endif
35951
35952#if 0 /*unused*/
35953DUK_INTERNAL void duk_debug_dump_heap(duk_heap *heap) {
35954 char buf[64+1];
35955
35956 DUK_D(DUK_DPRINT("=== heap %p ===", (void *) heap));
35957 DUK_D(DUK_DPRINT(" flags: 0x%08lx", (unsigned long) heap->flags));
35958
35959 /* Note: there is no standard formatter for function pointers */
35960#ifdef DUK_USE_GCC_PRAGMAS
35961#pragma GCC diagnostic push
35962#pragma GCC diagnostic ignored "-pedantic"
35963#endif
35964 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->alloc_func, sizeof(heap->alloc_func));
35965 DUK_D(DUK_DPRINT(" alloc_func: %s", (const char *) buf));
35966 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->realloc_func, sizeof(heap->realloc_func));
35967 DUK_D(DUK_DPRINT(" realloc_func: %s", (const char *) buf));
35968 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->free_func, sizeof(heap->free_func));
35969 DUK_D(DUK_DPRINT(" free_func: %s", (const char *) buf));
35970 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->fatal_func, sizeof(heap->fatal_func));
35971 DUK_D(DUK_DPRINT(" fatal_func: %s", (const char *) buf));
35972#ifdef DUK_USE_GCC_PRAGMAS
35973#pragma GCC diagnostic pop
35974#endif
35975
35976 DUK_D(DUK_DPRINT(" heap_udata: %p", (void *) heap->heap_udata));
35977
35978#ifdef DUK_USE_MARK_AND_SWEEP
35979#ifdef DUK_USE_VOLUNTARY_GC
35980 DUK_D(DUK_DPRINT(" mark-and-sweep trig counter: %ld", (long) heap->mark_and_sweep_trigger_counter));
35981#endif
35982 DUK_D(DUK_DPRINT(" mark-and-sweep rec depth: %ld", (long) heap->mark_and_sweep_recursion_depth));
35983 DUK_D(DUK_DPRINT(" mark-and-sweep base flags: 0x%08lx", (unsigned long) heap->mark_and_sweep_base_flags));
35984#endif
35985
35986 DUK_D(DUK_DPRINT(" lj.jmpbuf_ptr: %p", (void *) heap->lj.jmpbuf_ptr));
35987 DUK_D(DUK_DPRINT(" lj.type: %ld", (long) heap->lj.type));
35988 DUK_D(DUK_DPRINT(" lj.value1: %!T", (duk_tval *) &heap->lj.value1));
35989 DUK_D(DUK_DPRINT(" lj.value2: %!T", (duk_tval *) &heap->lj.value2));
35990 DUK_D(DUK_DPRINT(" lj.iserror: %ld", (long) heap->lj.iserror));
35991
35992 DUK_D(DUK_DPRINT(" handling_error: %ld", (long) heap->handling_error));
35993
35994 DUK_D(DUK_DPRINT(" heap_thread: %!@O", (duk_heaphdr *) heap->heap_thread));
35995 DUK_D(DUK_DPRINT(" curr_thread: %!@O", (duk_heaphdr *) heap->curr_thread));
35996 DUK_D(DUK_DPRINT(" heap_object: %!@O", (duk_heaphdr *) heap->heap_object));
35997
35998 DUK_D(DUK_DPRINT(" call_recursion_depth: %ld", (long) heap->call_recursion_depth));
35999 DUK_D(DUK_DPRINT(" call_recursion_limit: %ld", (long) heap->call_recursion_limit));
36000
36001 DUK_D(DUK_DPRINT(" hash_seed: 0x%08lx", (unsigned long) heap->hash_seed));
36002 DUK_D(DUK_DPRINT(" rnd_state: 0x%08lx", (unsigned long) heap->rnd_state));
36003
36004 duk__dump_strcache(heap);
36005
36006 duk__dump_heaphdr_list(heap, heap->heap_allocated, "heap allocated");
36007
36008#ifdef DUK_USE_REFERENCE_COUNTING
36009 duk__dump_heaphdr_list(heap, heap->refzero_list, "refcounting refzero list");
36010#endif
36011
36012#ifdef DUK_USE_MARK_AND_SWEEP
36013 duk__dump_heaphdr_list(heap, heap->finalize_list, "mark-and-sweep finalize list");
36014#endif
36015
36016 duk__dump_stringtable(heap);
36017
36018 /* heap->strs: not worth dumping */
36019}
36020#endif
36021
36022#endif /* DUK_USE_DEBUG */
36023#line 1 "duk_debug_vsnprintf.c"
36024/*
36025 * Custom formatter for debug printing, allowing Duktape specific data
36026 * structures (such as tagged values and heap objects) to be printed with
36027 * a nice format string. Because debug printing should not affect execution
36028 * state, formatting here must be independent of execution (see implications
36029 * below) and must not allocate memory.
36030 *
36031 * Custom format tags begin with a '%!' to safely distinguish them from
36032 * standard format tags. The following conversions are supported:
36033 *
36034 * %!T tagged value (duk_tval *)
36035 * %!O heap object (duk_heaphdr *)
36036 * %!I decoded bytecode instruction
36037 * %!C bytecode instruction opcode name (arg is long)
36038 *
36039 * Everything is serialized in a JSON-like manner. The default depth is one
36040 * level, internal prototype is not followed, and internal properties are not
36041 * serialized. The following modifiers change this behavior:
36042 *
36043 * @ print pointers
36044 * # print binary representations (where applicable)
36045 * d deep traversal of own properties (not prototype)
36046 * p follow prototype chain (useless without 'd')
36047 * i include internal properties (other than prototype)
36048 * x hexdump buffers
36049 * h heavy formatting
36050 *
36051 * For instance, the following serializes objects recursively, but does not
36052 * follow the prototype chain nor print internal properties: "%!dO".
36053 *
36054 * Notes:
36055 *
36056 * * Standard snprintf return value semantics seem to vary. This
36057 * implementation returns the number of bytes it actually wrote
36058 * (excluding the null terminator). If retval == buffer size,
36059 * output was truncated (except for corner cases).
36060 *
36061 * * Output format is intentionally different from Ecmascript
36062 * formatting requirements, as formatting here serves debugging
36063 * of internals.
36064 *
36065 * * Depth checking (and updating) is done in each type printer
36066 * separately, to allow them to call each other freely.
36067 *
36068 * * Some pathological structures might take ages to print (e.g.
36069 * self recursion with 100 properties pointing to the object
36070 * itself). To guard against these, each printer also checks
36071 * whether the output buffer is full; if so, early exit.
36072 *
36073 * * Reference loops are detected using a loop stack.
36074 */
36075
36076/* include removed: duk_internal.h */
36077
36078#ifdef DUK_USE_DEBUG
36079
36080#include <stdio.h>
36081#include <stdarg.h>
36082#include <string.h>
36083
36084/* list of conversion specifiers that terminate a format tag;
36085 * this is unfortunately guesswork.
36086 */
36087#define DUK__ALLOWED_STANDARD_SPECIFIERS "diouxXeEfFgGaAcsCSpnm"
36088
36089/* maximum length of standard format tag that we support */
36090#define DUK__MAX_FORMAT_TAG_LENGTH 32
36091
36092/* heapobj recursion depth when deep printing is selected */
36093#define DUK__DEEP_DEPTH_LIMIT 8
36094
36095/* maximum recursion depth for loop detection stacks */
36096#define DUK__LOOP_STACK_DEPTH 256
36097
36098/* must match bytecode defines now; build autogenerate? */
36099DUK_LOCAL const char *duk__bc_optab[64] = {
36100 "LDREG", "STREG", "LDCONST", "LDINT", "LDINTX", "MPUTOBJ", "MPUTOBJI", "MPUTARR", "MPUTARRI", "NEW",
36101 "NEWI", "REGEXP", "CSREG", "CSREGI", "GETVAR", "PUTVAR", "DECLVAR", "DELVAR", "CSVAR", "CSVARI",
36102 "CLOSURE", "GETPROP", "PUTPROP", "DELPROP", "CSPROP", "CSPROPI", "ADD", "SUB", "MUL", "DIV",
36103 "MOD", "BAND", "BOR", "BXOR", "BASL", "BLSR", "BASR", "EQ", "NEQ", "SEQ",
36104 "SNEQ", "GT", "GE", "LT", "LE", "IF", "JUMP", "RETURN", "CALL", "CALLI",
36105 "TRYCATCH", "EXTRA", "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
36106 "PREINCP", "PREDECP", "POSTINCP", "POSTDECP"
36107};
36108
36109DUK_LOCAL const char *duk__bc_extraoptab[256] = {
36110 "NOP", "INVALID", "LDTHIS", "LDUNDEF", "LDNULL", "LDTRUE", "LDFALSE", "NEWOBJ", "NEWARR", "SETALEN",
36111 "TYPEOF", "TYPEOFID", "INITENUM", "NEXTENUM", "INITSET", "INITSETI", "INITGET", "INITGETI", "ENDTRY", "ENDCATCH",
36112 "ENDFIN", "THROW", "INVLHS", "UNM", "UNP", "DEBUGGER", "BREAK", "CONTINUE", "BNOT", "LNOT",
36113 "INSTOF", "IN", "LABEL", "ENDLABEL", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36114 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36115
36116 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36117 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36118 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36119 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36120 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36121
36122 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36123 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36124 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36125 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36126 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36127
36128 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36129 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36130 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36131 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36132 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36133
36134 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36135 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36136 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36137 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36138 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36139
36140 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX"
36141};
36142
36143typedef struct duk__dprint_state duk__dprint_state;
36144struct duk__dprint_state {
36145 duk_fixedbuffer *fb;
36146
36147 /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice
36148 * to not couple these two mechanisms unnecessarily.
36149 */
36150 duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH];
36151 duk_int_t loop_stack_index;
36152 duk_int_t loop_stack_limit;
36153
36154 duk_int_t depth;
36155 duk_int_t depth_limit;
36156
36157 duk_bool_t pointer;
36158 duk_bool_t heavy;
36159 duk_bool_t binary;
36160 duk_bool_t follow_proto;
36161 duk_bool_t internal;
36162 duk_bool_t hexdump;
36163};
36164
36165/* helpers */
36166DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes);
36167DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h);
36168DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h);
36169DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv);
36170DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins);
36171DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
36172DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
36173DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h);
36174
36175DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
36176 duk_fixedbuffer *fb = st->fb;
36177
36178 if (st->heavy) {
36179 duk_fb_sprintf(fb, "(%p)", (void *) h);
36180 }
36181
36182 if (!h) {
36183 return;
36184 }
36185
36186 if (st->binary) {
36187 duk_size_t i;
36188 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
36189 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
36190 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
36191 }
36192 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
36193 }
36194
36195#ifdef DUK_USE_REFERENCE_COUNTING /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
36196 if (st->heavy) {
36197 duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld,"
36198 "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36199 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
36200 (void *) DUK_HEAPHDR_GET_PREV(NULL, h),
36201 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h),
36202 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
36203 (long) DUK_HEAPHDR_GET_TYPE(h),
36204 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
36205 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
36206 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
36207 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
36208 }
36209#else
36210 if (st->heavy) {
36211 duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36212 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
36213 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
36214 (long) DUK_HEAPHDR_GET_TYPE(h),
36215 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
36216 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
36217 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
36218 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
36219 }
36220#endif
36221}
36222
36223DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) {
36224 duk_fixedbuffer *fb = st->fb;
36225
36226 if (st->heavy) {
36227 duk_fb_sprintf(fb, "(%p)", (void *) h);
36228 }
36229
36230 if (!h) {
36231 return;
36232 }
36233
36234 if (st->binary) {
36235 duk_size_t i;
36236 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
36237 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
36238 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
36239 }
36240 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
36241 }
36242
36243#ifdef DUK_USE_REFERENCE_COUNTING
36244 if (st->heavy) {
36245 duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36246 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
36247 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
36248 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
36249 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
36250 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
36251 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
36252 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
36253 }
36254#else
36255 if (st->heavy) {
36256 duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36257 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
36258 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
36259 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
36260 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
36261 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
36262 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
36263 }
36264#endif
36265}
36266
36267DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) {
36268 duk_fixedbuffer *fb = st->fb;
36269 const duk_uint8_t *p;
36270 const duk_uint8_t *p_end;
36271
36272 /* terminal type: no depth check */
36273
36274 if (duk_fb_is_full(fb)) {
36275 return;
36276 }
36277
36278 duk__print_shared_heaphdr_string(st, &h->hdr);
36279
36280 if (!h) {
36281 duk_fb_put_cstring(fb, "NULL");
36282 return;
36283 }
36284
36285 p = DUK_HSTRING_GET_DATA(h);
36286 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
36287
36288 if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
36289 /* if property key begins with underscore, encode it with
36290 * forced quotes (e.g. "_Foo") to distinguish it from encoded
36291 * internal properties (e.g. \xffBar -> _Bar).
36292 */
36293 quotes = 1;
36294 }
36295
36296 if (quotes) {
36297 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
36298 }
36299 while (p < p_end) {
36300 duk_uint8_t ch = *p++;
36301
36302 /* two special escapes: '\' and '"', other printables as is */
36303 if (ch == '\\') {
36304 duk_fb_sprintf(fb, "\\\\");
36305 } else if (ch == '"') {
36306 duk_fb_sprintf(fb, "\\\"");
36307 } else if (ch >= 0x20 && ch <= 0x7e) {
36308 duk_fb_put_byte(fb, ch);
36309 } else if (ch == 0xff && !quotes) {
36310 /* encode \xffBar as _Bar if no quotes are applied, this is for
36311 * readable internal keys.
36312 */
36313 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
36314 } else {
36315 duk_fb_sprintf(fb, "\\x%02lx", (unsigned long) ch);
36316 }
36317 }
36318 if (quotes) {
36319 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
36320 }
36321#ifdef DUK_USE_REFERENCE_COUNTING
36322 /* XXX: limit to quoted strings only, to save keys from being cluttered? */
36323 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
36324#endif
36325}
36326
36327#ifdef DUK__COMMA
36328#undef DUK__COMMA
36329#endif
36330#define DUK__COMMA() do { \
36331 if (first) { \
36332 first = 0; \
36333 } else { \
36334 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \
36335 } \
36336 } while (0)
36337
36338DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
36339 duk_fixedbuffer *fb = st->fb;
36340 duk_uint_fast32_t i;
36341 duk_tval *tv;
36342 duk_hstring *key;
36343 duk_bool_t first = 1;
36344 const char *brace1 = "{";
36345 const char *brace2 = "}";
36346 duk_bool_t pushed_loopstack = 0;
36347
36348 if (duk_fb_is_full(fb)) {
36349 return;
36350 }
36351
36352 duk__print_shared_heaphdr(st, &h->hdr);
36353
36354 if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) {
36355 brace1 = "[";
36356 brace2 = "]";
36357 }
36358
36359 if (!h) {
36360 duk_fb_put_cstring(fb, "NULL");
36361 goto finished;
36362 }
36363
36364 if (st->depth >= st->depth_limit) {
36365 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
36366 duk_fb_sprintf(fb, "%sobject/compiledfunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36367 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
36368 duk_fb_sprintf(fb, "%sobject/nativefunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36369 } else if (DUK_HOBJECT_IS_THREAD(h)) {
36370 duk_fb_sprintf(fb, "%sobject/thread %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36371 } else {
36372 duk_fb_sprintf(fb, "%sobject %p%s", (const char *) brace1, (void *) h, (const char *) brace2); /* may be NULL */
36373 }
36374 return;
36375 }
36376
36377 for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) {
36378 if (st->loop_stack[i] == h) {
36379 duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36380 return;
36381 }
36382 }
36383
36384 /* after this, return paths should 'goto finished' for decrement */
36385 st->depth++;
36386
36387 if (st->loop_stack_index >= st->loop_stack_limit) {
36388 duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2);
36389 goto finished;
36390 }
36391 st->loop_stack[st->loop_stack_index++] = h;
36392 pushed_loopstack = 1;
36393
36394 /*
36395 * Notation: double underscore used for internal properties which are not
36396 * stored in the property allocation (e.g. '__valstack').
36397 */
36398
36399 duk_fb_put_cstring(fb, brace1);
36400
36401 if (DUK_HOBJECT_GET_PROPS(NULL, h)) {
36402 duk_uint32_t a_limit;
36403
36404 a_limit = DUK_HOBJECT_GET_ASIZE(h);
36405 if (st->internal) {
36406 /* dump all allocated entries, unused entries print as 'unused',
36407 * note that these may extend beyond current 'length' and look
36408 * a bit funny.
36409 */
36410 } else {
36411 /* leave out trailing 'unused' elements */
36412 while (a_limit > 0) {
36413 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1);
36414 if (!DUK_TVAL_IS_UNUSED(tv)) {
36415 break;
36416 }
36417 a_limit--;
36418 }
36419 }
36420
36421 for (i = 0; i < a_limit; i++) {
36422 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i);
36423 DUK__COMMA();
36424 duk__print_tval(st, tv);
36425 }
36426 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) {
36427 key = DUK_HOBJECT_E_GET_KEY(NULL, h, i);
36428 if (!key) {
36429 continue;
36430 }
36431 if (!st->internal &&
36432 DUK_HSTRING_GET_BYTELEN(key) > 0 &&
36433 DUK_HSTRING_GET_DATA(key)[0] == 0xff) {
36434 /* XXX: use DUK_HSTRING_FLAG_INTERNAL? */
36435 continue;
36436 }
36437 DUK__COMMA();
36438 duk__print_hstring(st, key, 0);
36439 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON);
36440 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) {
36441 duk_fb_sprintf(fb, "[get:%p,set:%p]",
36442 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get,
36443 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set);
36444 } else {
36445 tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v;
36446 duk__print_tval(st, tv);
36447 }
36448 if (st->heavy) {
36449 duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i));
36450 }
36451 }
36452 }
36453 if (st->internal) {
36454 if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
36455 DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
36456 } else {
36457 ;
36458 }
36459 if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
36460 DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
36461 } else {
36462 ;
36463 }
36464 if (DUK_HOBJECT_HAS_BOUND(h)) {
36465 DUK__COMMA(); duk_fb_sprintf(fb, "__bound:true");
36466 } else {
36467 ;
36468 }
36469 if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)) {
36470 DUK__COMMA(); duk_fb_sprintf(fb, "__compiledfunction:true");
36471 } else {
36472 ;
36473 }
36474 if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
36475 DUK__COMMA(); duk_fb_sprintf(fb, "__nativefunction:true");
36476 } else {
36477 ;
36478 }
36479 if (DUK_HOBJECT_HAS_THREAD(h)) {
36480 DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
36481 } else {
36482 ;
36483 }
36484 if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
36485 DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
36486 } else {
36487 ;
36488 }
36489 if (DUK_HOBJECT_HAS_STRICT(h)) {
36490 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
36491 } else {
36492 ;
36493 }
36494 if (DUK_HOBJECT_HAS_NEWENV(h)) {
36495 DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
36496 } else {
36497 ;
36498 }
36499 if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
36500 DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
36501 } else {
36502 ;
36503 }
36504 if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
36505 DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
36506 } else {
36507 ;
36508 }
36509 if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) {
36510 DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true");
36511 } else {
36512 ;
36513 }
36514 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) {
36515 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true");
36516 } else {
36517 ;
36518 }
36519 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) {
36520 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true");
36521 } else {
36522 ;
36523 }
36524 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
36525 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
36526 } else {
36527 ;
36528 }
36529 if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h)) {
36530 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_dukfunc:true");
36531 } else {
36532 ;
36533 }
36534 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
36535 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufferobj:true");
36536 } else {
36537 ;
36538 }
36539 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) {
36540 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true");
36541 } else {
36542 ;
36543 }
36544 }
36545 if (st->internal && DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
36546 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
36547 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
36548 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
36549 DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs);
36550 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
36551#if defined(DUK_USE_DEBUGGER_SUPPORT)
36552 DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line);
36553 DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line);
36554#endif
36555 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
36556 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
36557 } else if (st->internal && DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
36558 duk_hnativefunction *f = (duk_hnativefunction *) h;
36559 DUK__COMMA(); duk_fb_sprintf(fb, "__func:");
36560 duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func));
36561 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
36562 DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic);
36563 } else if (st->internal && DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
36564 duk_hbufferobject *b = (duk_hbufferobject *) h;
36565 DUK__COMMA(); duk_fb_sprintf(fb, "__buf:");
36566 duk__print_hbuffer(st, (duk_hbuffer *) b->buf);
36567 DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset);
36568 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length);
36569 DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
36570 DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
36571 } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
36572 duk_hthread *t = (duk_hthread *) h;
36573 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
36574 DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
36575 DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
36576 DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
36577 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%ld", (long) t->valstack_max);
36578 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%ld", (long) t->callstack_max);
36579 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%ld", (long) t->catchstack_max);
36580 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
36581 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
36582 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
36583 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
36584 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack);
36585 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%ld", (long) t->catchstack_size);
36586 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%ld", (long) t->catchstack_top);
36587 DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
36588 /* XXX: print built-ins array? */
36589
36590 }
36591#ifdef DUK_USE_REFERENCE_COUNTING
36592 if (st->internal) {
36593 DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
36594 }
36595#endif
36596 if (st->internal) {
36597 DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h));
36598 }
36599
36600 DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h); /* own pointer */
36601
36602 /* prototype should be last, for readability */
36603 if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) {
36604 if (st->follow_proto) {
36605 DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
36606 } else {
36607 DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
36608 }
36609 }
36610
36611 duk_fb_put_cstring(fb, brace2);
36612
36613#if defined(DUK_USE_HOBJECT_HASH_PART)
36614 if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) {
36615 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
36616 for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) {
36617 duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i);
36618 if (i > 0) {
36619 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA);
36620 }
36621 if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) {
36622 duk_fb_sprintf(fb, "u");
36623 } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) {
36624 duk_fb_sprintf(fb, "d");
36625 } else {
36626 duk_fb_sprintf(fb, "%ld", (long) h_idx);
36627 }
36628 }
36629 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
36630 }
36631#endif
36632
36633 finished:
36634 st->depth--;
36635 if (pushed_loopstack) {
36636 st->loop_stack_index--;
36637 st->loop_stack[st->loop_stack_index] = NULL;
36638 }
36639}
36640
36641#undef DUK__COMMA
36642
36643DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
36644 duk_fixedbuffer *fb = st->fb;
36645 duk_size_t i, n;
36646 duk_uint8_t *p;
36647
36648 if (duk_fb_is_full(fb)) {
36649 return;
36650 }
36651
36652 /* terminal type: no depth check */
36653
36654 if (!h) {
36655 duk_fb_put_cstring(fb, "NULL");
36656 return;
36657 }
36658
36659 if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
36660 if (DUK_HBUFFER_HAS_EXTERNAL(h)) {
36661 duk_hbuffer_external *g = (duk_hbuffer_external *) h;
36662 duk_fb_sprintf(fb, "buffer:external:%p:%ld",
36663 (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g),
36664 (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g));
36665 } else {
36666 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
36667 duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld",
36668 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g),
36669 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g));
36670 }
36671 } else {
36672 duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h));
36673 }
36674
36675#ifdef DUK_USE_REFERENCE_COUNTING
36676 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
36677#endif
36678
36679 if (st->hexdump) {
36680 duk_fb_sprintf(fb, "=[");
36681 n = DUK_HBUFFER_GET_SIZE(h);
36682 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h);
36683 for (i = 0; i < n; i++) {
36684 duk_fb_sprintf(fb, "%02lx", (unsigned long) p[i]);
36685 }
36686 duk_fb_sprintf(fb, "]");
36687 }
36688}
36689
36690DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
36691 duk_fixedbuffer *fb = st->fb;
36692
36693 if (duk_fb_is_full(fb)) {
36694 return;
36695 }
36696
36697 if (!h) {
36698 duk_fb_put_cstring(fb, "NULL");
36699 return;
36700 }
36701
36702 switch (DUK_HEAPHDR_GET_TYPE(h)) {
36703 case DUK_HTYPE_STRING:
36704 duk__print_hstring(st, (duk_hstring *) h, 1);
36705 break;
36706 case DUK_HTYPE_OBJECT:
36707 duk__print_hobject(st, (duk_hobject *) h);
36708 break;
36709 case DUK_HTYPE_BUFFER:
36710 duk__print_hbuffer(st, (duk_hbuffer *) h);
36711 break;
36712 default:
36713 duk_fb_sprintf(fb, "[unknown htype %ld]", (long) DUK_HEAPHDR_GET_TYPE(h));
36714 break;
36715 }
36716}
36717
36718DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
36719 duk_fixedbuffer *fb = st->fb;
36720
36721 if (duk_fb_is_full(fb)) {
36722 return;
36723 }
36724
36725 /* depth check is done when printing an actual type */
36726
36727 if (st->heavy) {
36728 duk_fb_sprintf(fb, "(%p)", (void *) tv);
36729 }
36730
36731 if (!tv) {
36732 duk_fb_put_cstring(fb, "NULL");
36733 return;
36734 }
36735
36736 if (st->binary) {
36737 duk_size_t i;
36738 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
36739 for (i = 0; i < (duk_size_t) sizeof(*tv); i++) {
36740 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)tv)[i]);
36741 }
36742 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
36743 }
36744
36745 if (st->heavy) {
36746 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
36747 }
36748 switch (DUK_TVAL_GET_TAG(tv)) {
36749 case DUK_TAG_UNDEFINED: {
36750 duk_fb_put_cstring(fb, "undefined");
36751 break;
36752 }
36753 case DUK_TAG_UNUSED: {
36754 duk_fb_put_cstring(fb, "unused");
36755 break;
36756 }
36757 case DUK_TAG_NULL: {
36758 duk_fb_put_cstring(fb, "null");
36759 break;
36760 }
36761 case DUK_TAG_BOOLEAN: {
36762 duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false");
36763 break;
36764 }
36765 case DUK_TAG_STRING: {
36766 /* Note: string is a terminal heap object, so no depth check here */
36767 duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1);
36768 break;
36769 }
36770 case DUK_TAG_OBJECT: {
36771 duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv));
36772 break;
36773 }
36774 case DUK_TAG_BUFFER: {
36775 duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv));
36776 break;
36777 }
36778 case DUK_TAG_POINTER: {
36779 duk_fb_sprintf(fb, "pointer:%p", (void *) DUK_TVAL_GET_POINTER(tv));
36780 break;
36781 }
36782 case DUK_TAG_LIGHTFUNC: {
36783 duk_c_function func;
36784 duk_small_uint_t lf_flags;
36785
36786 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
36787 duk_fb_sprintf(fb, "lightfunc:");
36788 duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func));
36789 duk_fb_sprintf(fb, ":%04lx", (long) lf_flags);
36790 break;
36791 }
36792#if defined(DUK_USE_FASTINT)
36793 case DUK_TAG_FASTINT:
36794#endif
36795 default: {
36796 /* IEEE double is approximately 16 decimal digits; print a couple extra */
36797 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
36798 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
36799 duk_fb_sprintf(fb, "%.18g", (double) DUK_TVAL_GET_NUMBER(tv));
36800 break;
36801 }
36802 }
36803 if (st->heavy) {
36804 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
36805 }
36806}
36807
36808DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
36809 duk_fixedbuffer *fb = st->fb;
36810 duk_small_int_t op;
36811 const char *op_name;
36812 const char *extraop_name;
36813
36814 op = (duk_small_int_t) DUK_DEC_OP(ins);
36815 op_name = duk__bc_optab[op];
36816
36817 /* XXX: option to fix opcode length so it lines up nicely */
36818
36819 if (op == DUK_OP_EXTRA) {
36820 extraop_name = duk__bc_extraoptab[DUK_DEC_A(ins)];
36821
36822 duk_fb_sprintf(fb, "%s %ld, %ld",
36823 (const char *) extraop_name, (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
36824 } else if (op == DUK_OP_JUMP) {
36825 duk_int_t diff1 = DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS; /* from next pc */
36826 duk_int_t diff2 = diff1 + 1; /* from curr pc */
36827
36828 duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
36829 (const char *) op_name, (long) diff1,
36830 (int) (diff2 >= 0 ? '+' : '-'), /* char format: use int */
36831 (long) (diff2 >= 0 ? diff2 : -diff2));
36832 } else {
36833 duk_fb_sprintf(fb, "%s %ld, %ld, %ld",
36834 (const char *) op_name, (long) DUK_DEC_A(ins),
36835 (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
36836 }
36837}
36838
36839DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) {
36840 duk_fixedbuffer *fb = st->fb;
36841
36842 if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) {
36843 duk_fb_sprintf(fb, "?(%ld)", (long) opcode);
36844 } else {
36845 duk_fb_sprintf(fb, "%s", (const char *) duk__bc_optab[opcode]);
36846 }
36847}
36848
36849DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) {
36850 duk_fixedbuffer fb;
36851 const char *p = format;
36852 const char *p_end = p + DUK_STRLEN(format);
36853 duk_int_t retval;
36854
36855 DUK_MEMZERO(&fb, sizeof(fb));
36856 fb.buffer = (duk_uint8_t *) str;
36857 fb.length = size;
36858 fb.offset = 0;
36859 fb.truncated = 0;
36860
36861 while (p < p_end) {
36862 char ch = *p++;
36863 const char *p_begfmt = NULL;
36864 duk_bool_t got_exclamation = 0;
36865 duk_bool_t got_long = 0; /* %lf, %ld etc */
36866 duk__dprint_state st;
36867
36868 if (ch != DUK_ASC_PERCENT) {
36869 duk_fb_put_byte(&fb, (duk_uint8_t) ch);
36870 continue;
36871 }
36872
36873 /*
36874 * Format tag parsing. Since we don't understand all the
36875 * possible format tags allowed, we just scan for a terminating
36876 * specifier and keep track of relevant modifiers that we do
36877 * understand. See man 3 printf.
36878 */
36879
36880 DUK_MEMZERO(&st, sizeof(st));
36881 st.fb = &fb;
36882 st.depth = 0;
36883 st.depth_limit = 1;
36884 st.loop_stack_index = 0;
36885 st.loop_stack_limit = DUK__LOOP_STACK_DEPTH;
36886
36887 p_begfmt = p - 1;
36888 while (p < p_end) {
36889 ch = *p++;
36890
36891 if (ch == DUK_ASC_STAR) {
36892 /* unsupported: would consume multiple args */
36893 goto error;
36894 } else if (ch == DUK_ASC_PERCENT) {
36895 duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT);
36896 break;
36897 } else if (ch == DUK_ASC_EXCLAMATION) {
36898 got_exclamation = 1;
36899 } else if (!got_exclamation && ch == DUK_ASC_LC_L) {
36900 got_long = 1;
36901 } else if (got_exclamation && ch == DUK_ASC_LC_D) {
36902 st.depth_limit = DUK__DEEP_DEPTH_LIMIT;
36903 } else if (got_exclamation && ch == DUK_ASC_LC_P) {
36904 st.follow_proto = 1;
36905 } else if (got_exclamation && ch == DUK_ASC_LC_I) {
36906 st.internal = 1;
36907 } else if (got_exclamation && ch == DUK_ASC_LC_X) {
36908 st.hexdump = 1;
36909 } else if (got_exclamation && ch == DUK_ASC_LC_H) {
36910 st.heavy = 1;
36911 } else if (got_exclamation && ch == DUK_ASC_ATSIGN) {
36912 st.pointer = 1;
36913 } else if (got_exclamation && ch == DUK_ASC_HASH) {
36914 st.binary = 1;
36915 } else if (got_exclamation && ch == DUK_ASC_UC_T) {
36916 duk_tval *t = va_arg(ap, duk_tval *);
36917 if (st.pointer && !st.heavy) {
36918 duk_fb_sprintf(&fb, "(%p)", (void *) t);
36919 }
36920 duk__print_tval(&st, t);
36921 break;
36922 } else if (got_exclamation && ch == DUK_ASC_UC_O) {
36923 duk_heaphdr *t = va_arg(ap, duk_heaphdr *);
36924 if (st.pointer && !st.heavy) {
36925 duk_fb_sprintf(&fb, "(%p)", (void *) t);
36926 }
36927 duk__print_heaphdr(&st, t);
36928 break;
36929 } else if (got_exclamation && ch == DUK_ASC_UC_I) {
36930 duk_instr_t t = va_arg(ap, duk_instr_t);
36931 duk__print_instr(&st, t);
36932 break;
36933 } else if (got_exclamation && ch == DUK_ASC_UC_C) {
36934 long t = va_arg(ap, long);
36935 duk__print_opcode(&st, (duk_small_int_t) t);
36936 break;
36937 } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) {
36938 char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH];
36939 duk_size_t fmtlen;
36940
36941 DUK_ASSERT(p >= p_begfmt);
36942 fmtlen = (duk_size_t) (p - p_begfmt);
36943 if (fmtlen >= sizeof(fmtbuf)) {
36944 /* format is too large, abort */
36945 goto error;
36946 }
36947 DUK_MEMZERO(fmtbuf, sizeof(fmtbuf));
36948 DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen);
36949
36950 /* assume exactly 1 arg, which is why '*' is forbidden; arg size still
36951 * depends on type though.
36952 */
36953
36954 if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) {
36955 /* %f and %lf both consume a 'long' */
36956 double arg = va_arg(ap, double);
36957 duk_fb_sprintf(&fb, fmtbuf, arg);
36958 } else if (ch == DUK_ASC_LC_D && got_long) {
36959 /* %ld */
36960 long arg = va_arg(ap, long);
36961 duk_fb_sprintf(&fb, fmtbuf, arg);
36962 } else if (ch == DUK_ASC_LC_D) {
36963 /* %d; only 16 bits are guaranteed */
36964 int arg = va_arg(ap, int);
36965 duk_fb_sprintf(&fb, fmtbuf, arg);
36966 } else if (ch == DUK_ASC_LC_U && got_long) {
36967 /* %lu */
36968 unsigned long arg = va_arg(ap, unsigned long);
36969 duk_fb_sprintf(&fb, fmtbuf, arg);
36970 } else if (ch == DUK_ASC_LC_U) {
36971 /* %u; only 16 bits are guaranteed */
36972 unsigned int arg = va_arg(ap, unsigned int);
36973 duk_fb_sprintf(&fb, fmtbuf, arg);
36974 } else if (ch == DUK_ASC_LC_X && got_long) {
36975 /* %lx */
36976 unsigned long arg = va_arg(ap, unsigned long);
36977 duk_fb_sprintf(&fb, fmtbuf, arg);
36978 } else if (ch == DUK_ASC_LC_X) {
36979 /* %x; only 16 bits are guaranteed */
36980 unsigned int arg = va_arg(ap, unsigned int);
36981 duk_fb_sprintf(&fb, fmtbuf, arg);
36982 } else if (ch == DUK_ASC_LC_S) {
36983 /* %s */
36984 const char *arg = va_arg(ap, const char *);
36985 if (arg == NULL) {
36986 /* '%s' and NULL is not portable, so special case
36987 * it for debug printing.
36988 */
36989 duk_fb_sprintf(&fb, "NULL");
36990 } else {
36991 duk_fb_sprintf(&fb, fmtbuf, arg);
36992 }
36993 } else if (ch == DUK_ASC_LC_P) {
36994 /* %p */
36995 void *arg = va_arg(ap, void *);
36996 if (arg == NULL) {
36997 /* '%p' and NULL is portable, but special case it
36998 * anyway to get a standard NULL marker in logs.
36999 */
37000 duk_fb_sprintf(&fb, "NULL");
37001 } else {
37002 duk_fb_sprintf(&fb, fmtbuf, arg);
37003 }
37004 } else if (ch == DUK_ASC_LC_C) {
37005 /* '%c', passed concretely as int */
37006 int arg = va_arg(ap, int);
37007 duk_fb_sprintf(&fb, fmtbuf, arg);
37008 } else {
37009 /* Should not happen. */
37010 duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)", (const char *) fmtbuf);
37011 }
37012 break;
37013 } else {
37014 /* ignore */
37015 }
37016 }
37017 }
37018 goto done;
37019
37020 error:
37021 duk_fb_put_cstring(&fb, "FMTERR");
37022 /* fall through */
37023
37024 done:
37025 retval = (duk_int_t) fb.offset;
37026 duk_fb_put_byte(&fb, (duk_uint8_t) 0);
37027
37028 /* return total chars written excluding terminator */
37029 return retval;
37030}
37031
37032#if 0 /*unused*/
37033DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) {
37034 duk_int_t retval;
37035 va_list ap;
37036 va_start(ap, format);
37037 retval = duk_debug_vsnprintf(str, size, format, ap);
37038 va_end(ap);
37039 return retval;
37040}
37041#endif
37042
37043/* Formatting function pointers is tricky: there is no standard pointer for
37044 * function pointers and the size of a function pointer may depend on the
37045 * specific pointer type. This helper formats a function pointer based on
37046 * its memory layout to get something useful on most platforms.
37047 */
37048DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) {
37049 duk_size_t i;
37050 duk_uint8_t *p = (duk_uint8_t *) buf;
37051 duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
37052
37053 DUK_MEMZERO(buf, buf_size);
37054
37055 for (i = 0; i < fptr_size; i++) {
37056 duk_int_t left = (duk_int_t) (p_end - p);
37057 duk_uint8_t ch;
37058 if (left <= 0) {
37059 break;
37060 }
37061
37062 /* Quite approximate but should be useful for little and big endian. */
37063#ifdef DUK_USE_INTEGER_BE
37064 ch = fptr[i];
37065#else
37066 ch = fptr[fptr_size - 1 - i];
37067#endif
37068 p += DUK_SNPRINTF((char *) p, left, "%02lx", (unsigned long) ch);
37069 }
37070}
37071
37072#endif /* DUK_USE_DEBUG */
37073#line 1 "duk_debugger.c"
37074/*
37075 * Duktape debugger
37076 */
37077
37078/* include removed: duk_internal.h */
37079
37080#if defined(DUK_USE_DEBUGGER_SUPPORT)
37081
37082/*
37083 * Helper structs
37084 */
37085
37086typedef union {
37087 void *p;
37088 duk_uint_t b[1];
37089 /* Use b[] to access the size of the union, which is strictly not
37090 * correct. Can't use fixed size unless there's feature detection
37091 * for pointer byte size.
37092 */
37093} duk__ptr_union;
37094
37095/*
37096 * Detach handling
37097 */
37098
37099#define DUK__SET_CONN_BROKEN(thr,reason) do { \
37100 /* For now shared handler is fine. */ \
37101 duk__debug_do_detach1((thr)->heap, (reason)); \
37102 } while (0)
37103
37104DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
37105 /* Can be called multiple times with no harm. Mark the transport
37106 * bad (dbg_read_cb == NULL) and clear state except for the detached
37107 * callback and the udata field. The detached callback is delayed
37108 * to the message loop so that it can be called between messages;
37109 * this avoids corner cases related to immediate debugger reattach
37110 * inside the detached callback.
37111 */
37112
37113 if (heap->dbg_detaching) {
37114 DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1"));
37115 return;
37116 }
37117
37118 DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));
37119
37120 heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */
37121
37122 if (heap->dbg_write_cb != NULL) {
37123 duk_hthread *thr;
37124
37125 thr = heap->heap_thread;
37126 DUK_ASSERT(thr != NULL);
37127
37128 duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING);
37129 duk_debug_write_int(thr, reason);
37130 duk_debug_write_eom(thr);
37131 }
37132
37133 heap->dbg_read_cb = NULL;
37134 heap->dbg_write_cb = NULL;
37135 heap->dbg_peek_cb = NULL;
37136 heap->dbg_read_flush_cb = NULL;
37137 heap->dbg_write_flush_cb = NULL;
37138 heap->dbg_request_cb = NULL;
37139 /* heap->dbg_detached_cb: keep */
37140 /* heap->dbg_udata: keep */
37141 /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
37142 heap->dbg_paused = 0;
37143 heap->dbg_state_dirty = 0;
37144 heap->dbg_force_restart = 0;
37145 heap->dbg_step_type = 0;
37146 heap->dbg_step_thread = NULL;
37147 heap->dbg_step_csindex = 0;
37148 heap->dbg_step_startline = 0;
37149 heap->dbg_have_next_byte = 0;
37150
37151 /* Ensure there are no stale active breakpoint pointers.
37152 * Breakpoint list is currently kept - we could empty it
37153 * here but we'd need to handle refcounts correctly, and
37154 * we'd need a 'thr' reference for that.
37155 *
37156 * XXX: clear breakpoint on either attach or detach?
37157 */
37158 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
37159}
37160
37161DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
37162 duk_debug_detached_function detached_cb;
37163 void *detached_udata;
37164
37165 /* Safe to call multiple times. */
37166
37167 detached_cb = heap->dbg_detached_cb;
37168 detached_udata = heap->dbg_udata;
37169 heap->dbg_detached_cb = NULL;
37170 heap->dbg_udata = NULL;
37171
37172 if (detached_cb) {
37173 /* Careful here: state must be wiped before the call
37174 * so that we can cleanly handle a re-attach from
37175 * inside the callback.
37176 */
37177 DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
37178 detached_cb(detached_udata);
37179 }
37180
37181 heap->dbg_detaching = 0;
37182}
37183
37184DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
37185 duk__debug_do_detach1(heap, 0);
37186 duk__debug_do_detach2(heap);
37187}
37188
37189/* Called on a read/write error: NULL all callbacks except the detached
37190 * callback so that we never accidentally call them after a read/write
37191 * error has been indicated. This is especially important for the transport
37192 * I/O callbacks to fulfill guaranteed callback semantics.
37193 */
37194DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
37195 duk_heap *heap;
37196 heap = thr->heap;
37197 DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached"));
37198 heap->dbg_read_cb = NULL;
37199 heap->dbg_write_cb = NULL; /* this is especially critical to avoid another write call in detach1() */
37200 heap->dbg_peek_cb = NULL;
37201 heap->dbg_read_flush_cb = NULL;
37202 heap->dbg_write_flush_cb = NULL;
37203 heap->dbg_request_cb = NULL;
37204 /* keep heap->dbg_detached_cb */
37205}
37206
37207/*
37208 * Debug connection peek and flush primitives
37209 */
37210
37211DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
37212 duk_heap *heap;
37213
37214 DUK_ASSERT(thr != NULL);
37215 heap = thr->heap;
37216 DUK_ASSERT(heap != NULL);
37217
37218 if (heap->dbg_read_cb == NULL) {
37219 DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)"));
37220 return 0;
37221 }
37222 if (heap->dbg_peek_cb == NULL) {
37223 DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)"));
37224 return 0;
37225 }
37226
37227 return (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
37228}
37229
37230DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
37231 duk_heap *heap;
37232
37233 DUK_ASSERT(thr != NULL);
37234 heap = thr->heap;
37235 DUK_ASSERT(heap != NULL);
37236
37237 if (heap->dbg_read_cb == NULL) {
37238 DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore"));
37239 return;
37240 }
37241 if (heap->dbg_read_flush_cb == NULL) {
37242 DUK_DD(DUK_DDPRINT("no read flush callback, ignore"));
37243 return;
37244 }
37245
37246 heap->dbg_read_flush_cb(heap->dbg_udata);
37247}
37248
37249DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
37250 duk_heap *heap;
37251
37252 DUK_ASSERT(thr != NULL);
37253 heap = thr->heap;
37254 DUK_ASSERT(heap != NULL);
37255
37256 if (heap->dbg_read_cb == NULL) {
37257 DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore"));
37258 return;
37259 }
37260 if (heap->dbg_write_flush_cb == NULL) {
37261 DUK_DD(DUK_DDPRINT("no write flush callback, ignore"));
37262 return;
37263 }
37264
37265 heap->dbg_write_flush_cb(heap->dbg_udata);
37266}
37267
37268/*
37269 * Debug connection skip primitives
37270 */
37271
37272/* Skip fully. */
37273DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) {
37274 duk_uint8_t dummy[64];
37275 duk_size_t now;
37276
37277 DUK_ASSERT(thr != NULL);
37278
37279 while (length > 0) {
37280 now = (length > sizeof(dummy) ? sizeof(dummy) : length);
37281 duk_debug_read_bytes(thr, dummy, now);
37282 length -= now;
37283 }
37284}
37285
37286DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
37287 DUK_ASSERT(thr != NULL);
37288
37289 (void) duk_debug_read_byte(thr);
37290}
37291
37292/*
37293 * Debug connection read primitives
37294 */
37295
37296/* Peek ahead in the stream one byte. */
37297DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) {
37298 /* It is important not to call this if the last byte read was an EOM.
37299 * Reading ahead in this scenario would cause unnecessary blocking if
37300 * another message is not available.
37301 */
37302
37303 duk_uint8_t x;
37304
37305 x = duk_debug_read_byte(thr);
37306 thr->heap->dbg_have_next_byte = 1;
37307 thr->heap->dbg_next_byte = x;
37308 return x;
37309}
37310
37311/* Read fully. */
37312DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
37313 duk_heap *heap;
37314 duk_uint8_t *p;
37315 duk_size_t left;
37316 duk_size_t got;
37317
37318 DUK_ASSERT(thr != NULL);
37319 heap = thr->heap;
37320 DUK_ASSERT(heap != NULL);
37321
37322 if (heap->dbg_read_cb == NULL) {
37323 DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
37324 goto fail;
37325 }
37326
37327 /* NOTE: length may be zero */
37328 p = data;
37329 if (length >= 1 && heap->dbg_have_next_byte) {
37330 heap->dbg_have_next_byte = 0;
37331 *p++ = heap->dbg_next_byte;
37332 }
37333 for (;;) {
37334 left = (duk_size_t) ((data + length) - p);
37335 if (left == 0) {
37336 break;
37337 }
37338 DUK_ASSERT(heap->dbg_read_cb != NULL);
37339 DUK_ASSERT(left >= 1);
37340#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
37341 left = 1;
37342#endif
37343 got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
37344 if (got == 0 || got > left) {
37345 DUK_D(DUK_DPRINT("connection error during read, return zero data"));
37346 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
37347 DUK__SET_CONN_BROKEN(thr, 1);
37348 goto fail;
37349 }
37350 p += got;
37351 }
37352 return;
37353
37354 fail:
37355 DUK_MEMZERO((void *) data, (size_t) length);
37356}
37357
37358DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
37359 duk_uint8_t x;
37360
37361 x = 0; /* just in case callback is broken and won't write 'x' */
37362 duk_debug_read_bytes(thr, &x, 1);
37363 return x;
37364}
37365
37366DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
37367 duk_uint8_t buf[4];
37368
37369 DUK_ASSERT(thr != NULL);
37370
37371 duk_debug_read_bytes(thr, buf, 4);
37372 return ((duk_uint32_t) buf[0] << 24) |
37373 ((duk_uint32_t) buf[1] << 16) |
37374 ((duk_uint32_t) buf[2] << 8) |
37375 (duk_uint32_t) buf[3];
37376}
37377
37378DUK_LOCAL duk_uint32_t duk__debug_read_int32_raw(duk_hthread *thr) {
37379 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
37380}
37381
37382DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) {
37383 duk_uint8_t buf[2];
37384
37385 DUK_ASSERT(thr != NULL);
37386
37387 duk_debug_read_bytes(thr, buf, 2);
37388 return ((duk_uint16_t) buf[0] << 8) |
37389 (duk_uint16_t) buf[1];
37390}
37391
37392DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
37393 duk_small_uint_t x;
37394 duk_small_uint_t t;
37395
37396 DUK_ASSERT(thr != NULL);
37397
37398 x = duk_debug_read_byte(thr);
37399 if (x >= 0xc0) {
37400 t = duk_debug_read_byte(thr);
37401 return (duk_int32_t) (((x - 0xc0) << 8) + t);
37402 } else if (x >= 0x80) {
37403 return (duk_int32_t) (x - 0x80);
37404 } else if (x == DUK_DBG_IB_INT4) {
37405 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
37406 }
37407
37408 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
37409 DUK__SET_CONN_BROKEN(thr, 1);
37410 return 0;
37411}
37412
37413DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
37414 duk_context *ctx = (duk_context *) thr;
37415 duk_uint8_t buf[31];
37416 duk_uint8_t *p;
37417
37418 if (len <= sizeof(buf)) {
37419 duk_debug_read_bytes(thr, buf, (duk_size_t) len);
37420 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
37421 } else {
37422 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
37423 DUK_ASSERT(p != NULL);
37424 duk_debug_read_bytes(thr, p, (duk_size_t) len);
37425 duk_to_string(ctx, -1);
37426 }
37427
37428 return duk_require_hstring(ctx, -1);
37429}
37430
37431DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
37432 duk_context *ctx = (duk_context *) thr;
37433 duk_small_uint_t x;
37434 duk_uint32_t len;
37435
37436 DUK_ASSERT(thr != NULL);
37437
37438 x = duk_debug_read_byte(thr);
37439 if (x >= 0x60 && x <= 0x7f) {
37440 /* For short strings, use a fixed temp buffer. */
37441 len = (duk_uint32_t) (x - 0x60);
37442 } else if (x == DUK_DBG_IB_STR2) {
37443 len = (duk_uint32_t) duk__debug_read_uint16_raw(thr);
37444 } else if (x == DUK_DBG_IB_STR4) {
37445 len = (duk_uint32_t) duk__debug_read_uint32_raw(thr);
37446 } else {
37447 goto fail;
37448 }
37449
37450 return duk__debug_read_hstring_raw(thr, len);
37451
37452 fail:
37453 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
37454 DUK__SET_CONN_BROKEN(thr, 1);
37455 duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* always push some string */
37456 return duk_require_hstring(ctx, -1);
37457}
37458
37459DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
37460 duk_context *ctx = (duk_context *) thr;
37461 duk_uint8_t *p;
37462
37463 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
37464 DUK_ASSERT(p != NULL);
37465 duk_debug_read_bytes(thr, p, (duk_size_t) len);
37466
37467 return duk_require_hbuffer(ctx, -1);
37468}
37469
37470DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
37471 duk_small_uint_t x;
37472 duk__ptr_union pu;
37473
37474 DUK_ASSERT(thr != NULL);
37475
37476 x = duk_debug_read_byte(thr);
37477 if (x != sizeof(pu)) {
37478 goto fail;
37479 }
37480 duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu));
37481#if defined(DUK_USE_INTEGER_LE)
37482 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
37483#endif
37484 return (void *) pu.p;
37485
37486 fail:
37487 DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
37488 DUK__SET_CONN_BROKEN(thr, 1);
37489 return (void *) NULL;
37490}
37491
37492DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
37493 duk_double_union du;
37494
37495 DUK_ASSERT(sizeof(du.uc) == 8);
37496 duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc));
37497 DUK_DBLUNION_DOUBLE_NTOH(&du);
37498 return du.d;
37499}
37500
37501#if 0
37502DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) {
37503 duk_small_uint_t x;
37504
37505 DUK_ASSERT(thr != NULL);
37506
37507 x = duk_debug_read_byte(thr);
37508 if (x != DUK_DBG_IB_HEAPPTR) {
37509 goto fail;
37510 }
37511
37512 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37513
37514 fail:
37515 DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr"));
37516 DUK__SET_CONN_BROKEN(thr, 1);
37517 return NULL;
37518}
37519#endif
37520
37521DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
37522 duk_small_uint_t x;
37523
37524 DUK_ASSERT(thr != NULL);
37525
37526 x = duk_debug_read_byte(thr);
37527 switch (x) {
37528 case DUK_DBG_IB_OBJECT:
37529 case DUK_DBG_IB_POINTER:
37530 case DUK_DBG_IB_HEAPPTR:
37531 /* Accept any pointer-like value; for 'object' dvalue, read
37532 * and ignore the class number.
37533 */
37534 if (x == DUK_DBG_IB_OBJECT) {
37535 duk_debug_skip_byte(thr);
37536 }
37537 break;
37538 default:
37539 goto fail;
37540 }
37541
37542 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37543
37544 fail:
37545 DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)"));
37546 DUK__SET_CONN_BROKEN(thr, 1);
37547 return NULL;
37548}
37549
37550DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
37551 duk_context *ctx = (duk_context *) thr;
37552 duk_uint8_t x;
37553 duk_uint_t t;
37554 duk_uint32_t len;
37555
37556 DUK_ASSERT(thr != NULL);
37557
37558 x = duk_debug_read_byte(thr);
37559
37560 if (x >= 0xc0) {
37561 t = (duk_uint_t) (x - 0xc0);
37562 t = (t << 8) + duk_debug_read_byte(thr);
37563 duk_push_uint(ctx, (duk_uint_t) t);
37564 goto return_ptr;
37565 }
37566 if (x >= 0x80) {
37567 duk_push_uint(ctx, (duk_uint_t) (x - 0x80));
37568 goto return_ptr;
37569 }
37570 if (x >= 0x60) {
37571 len = (duk_uint32_t) (x - 0x60);
37572 duk__debug_read_hstring_raw(thr, len);
37573 goto return_ptr;
37574 }
37575
37576 switch (x) {
37577 case DUK_DBG_IB_INT4: {
37578 duk_int32_t i = duk__debug_read_int32_raw(thr);
37579 duk_push_i32(ctx, i);
37580 break;
37581 }
37582 case DUK_DBG_IB_STR4: {
37583 len = duk__debug_read_uint32_raw(thr);
37584 duk__debug_read_hstring_raw(thr, len);
37585 break;
37586 }
37587 case DUK_DBG_IB_STR2: {
37588 len = duk__debug_read_uint16_raw(thr);
37589 duk__debug_read_hstring_raw(thr, len);
37590 break;
37591 }
37592 case DUK_DBG_IB_BUF4: {
37593 len = duk__debug_read_uint32_raw(thr);
37594 duk__debug_read_hbuffer_raw(thr, len);
37595 break;
37596 }
37597 case DUK_DBG_IB_BUF2: {
37598 len = duk__debug_read_uint16_raw(thr);
37599 duk__debug_read_hbuffer_raw(thr, len);
37600 break;
37601 }
37602 case DUK_DBG_IB_UNDEFINED: {
37603 duk_push_undefined(ctx);
37604 break;
37605 }
37606 case DUK_DBG_IB_NULL: {
37607 duk_push_null(ctx);
37608 break;
37609 }
37610 case DUK_DBG_IB_TRUE: {
37611 duk_push_true(ctx);
37612 break;
37613 }
37614 case DUK_DBG_IB_FALSE: {
37615 duk_push_false(ctx);
37616 break;
37617 }
37618 case DUK_DBG_IB_NUMBER: {
37619 duk_double_t d;
37620 d = duk__debug_read_double_raw(thr);
37621 duk_push_number(ctx, d);
37622 break;
37623 }
37624 case DUK_DBG_IB_OBJECT: {
37625 duk_heaphdr *h;
37626 duk_debug_skip_byte(thr);
37627 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37628 duk_push_heapptr(thr, (void *) h);
37629 break;
37630 }
37631 case DUK_DBG_IB_POINTER: {
37632 void *ptr;
37633 ptr = duk__debug_read_pointer_raw(thr);
37634 duk_push_pointer(thr, ptr);
37635 break;
37636 }
37637 case DUK_DBG_IB_LIGHTFUNC: {
37638 /* XXX: Not needed for now, so not implemented. Note that
37639 * function pointers may have different size/layout than
37640 * a void pointer.
37641 */
37642 DUK_D(DUK_DPRINT("reading lightfunc values unimplemented"));
37643 goto fail;
37644 }
37645 case DUK_DBG_IB_HEAPPTR: {
37646 duk_heaphdr *h;
37647 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37648 duk_push_heapptr(thr, (void *) h);
37649 break;
37650 }
37651 case DUK_DBG_IB_UNUSED: /* unused: not accepted in inbound messages */
37652 default:
37653 goto fail;
37654 }
37655
37656 return_ptr:
37657 return DUK_GET_TVAL_NEGIDX(thr, -1);
37658
37659 fail:
37660 DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
37661 DUK__SET_CONN_BROKEN(thr, 1);
37662 return NULL;
37663}
37664
37665/*
37666 * Debug connection write primitives
37667 */
37668
37669/* Write fully. */
37670DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) {
37671 duk_heap *heap;
37672 const duk_uint8_t *p;
37673 duk_size_t left;
37674 duk_size_t got;
37675
37676 DUK_ASSERT(thr != NULL);
37677 DUK_ASSERT(length == 0 || data != NULL);
37678 heap = thr->heap;
37679 DUK_ASSERT(heap != NULL);
37680
37681 if (heap->dbg_write_cb == NULL) {
37682 DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length));
37683 return;
37684 }
37685 if (length == 0) {
37686 /* Avoid doing an actual write callback with length == 0,
37687 * because that's reserved for a write flush.
37688 */
37689 return;
37690 }
37691 DUK_ASSERT(data != NULL);
37692
37693 p = data;
37694 for (;;) {
37695 left = (duk_size_t) ((data + length) - p);
37696 if (left == 0) {
37697 break;
37698 }
37699 DUK_ASSERT(heap->dbg_write_cb != NULL);
37700 DUK_ASSERT(left >= 1);
37701#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
37702 left = 1;
37703#endif
37704 got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
37705 if (got == 0 || got > left) {
37706 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
37707 DUK_D(DUK_DPRINT("connection error during write"));
37708 DUK__SET_CONN_BROKEN(thr, 1);
37709 return;
37710 }
37711 p += got;
37712 }
37713}
37714
37715DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
37716 duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1);
37717}
37718
37719DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
37720 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
37721}
37722
37723DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
37724 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
37725}
37726
37727#if defined(DUK_USE_DEBUGGER_INSPECT)
37728DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) {
37729 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
37730}
37731#endif
37732
37733DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) {
37734 duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE);
37735}
37736
37737/* Write signed 32-bit integer. */
37738DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
37739 duk_uint8_t buf[5];
37740 duk_size_t len;
37741
37742 DUK_ASSERT(thr != NULL);
37743
37744 if (x >= 0 && x <= 0x3fL) {
37745 buf[0] = (duk_uint8_t) (0x80 + x);
37746 len = 1;
37747 } else if (x >= 0 && x <= 0x3fffL) {
37748 buf[0] = (duk_uint8_t) (0xc0 + (x >> 8));
37749 buf[1] = (duk_uint8_t) (x & 0xff);
37750 len = 2;
37751 } else {
37752 /* Signed integers always map to 4 bytes now. */
37753 buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4;
37754 buf[1] = (duk_uint8_t) ((x >> 24) & 0xff);
37755 buf[2] = (duk_uint8_t) ((x >> 16) & 0xff);
37756 buf[3] = (duk_uint8_t) ((x >> 8) & 0xff);
37757 buf[4] = (duk_uint8_t) (x & 0xff);
37758 len = 5;
37759 }
37760 duk_debug_write_bytes(thr, buf, len);
37761}
37762
37763/* Write unsigned 32-bit integer. */
37764DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) {
37765 /* The debugger protocol doesn't support a plain integer encoding for
37766 * the full 32-bit unsigned range (only 32-bit signed). For now,
37767 * unsigned 32-bit values simply written as signed ones. This is not
37768 * a concrete issue except for 32-bit heaphdr fields. Proper solutions
37769 * would be to (a) write such integers as IEEE doubles or (b) add an
37770 * unsigned 32-bit dvalue.
37771 */
37772 if (x >= 0x80000000UL) {
37773 DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer",
37774 (long) x));
37775 }
37776 duk_debug_write_int(thr, (duk_int32_t) x);
37777}
37778
37779DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) {
37780 duk_uint8_t buf[5];
37781 duk_size_t buflen;
37782
37783 DUK_ASSERT(thr != NULL);
37784 DUK_ASSERT(length == 0 || data != NULL);
37785
37786 if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) {
37787 /* For strings, special form for short lengths. */
37788 buf[0] = (duk_uint8_t) (0x60 + length);
37789 buflen = 1;
37790 } else if (length <= 0xffffUL) {
37791 buf[0] = (duk_uint8_t) (marker_base + 1);
37792 buf[1] = (duk_uint8_t) (length >> 8);
37793 buf[2] = (duk_uint8_t) (length & 0xff);
37794 buflen = 3;
37795 } else {
37796 buf[0] = (duk_uint8_t) marker_base;
37797 buf[1] = (duk_uint8_t) (length >> 24);
37798 buf[2] = (duk_uint8_t) ((length >> 16) & 0xff);
37799 buf[3] = (duk_uint8_t) ((length >> 8) & 0xff);
37800 buf[4] = (duk_uint8_t) (length & 0xff);
37801 buflen = 5;
37802 }
37803
37804 duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen);
37805 duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length);
37806}
37807
37808DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) {
37809 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4);
37810}
37811
37812DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) {
37813 DUK_ASSERT(thr != NULL);
37814
37815 duk_debug_write_string(thr,
37816 data,
37817 data ? DUK_STRLEN(data) : 0);
37818}
37819
37820DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
37821 DUK_ASSERT(thr != NULL);
37822
37823 /* XXX: differentiate null pointer from empty string? */
37824 duk_debug_write_string(thr,
37825 (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL),
37826 (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0));
37827}
37828
37829DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
37830 duk_context *ctx = (duk_context *) thr;
37831 duk_debug_write_hstring(thr, duk_safe_to_hstring(ctx, -1));
37832}
37833
37834DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
37835 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4);
37836}
37837
37838DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
37839 DUK_ASSERT(thr != NULL);
37840
37841 duk_debug_write_buffer(thr,
37842 (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL),
37843 (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
37844}
37845
37846DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) {
37847 duk_uint8_t buf[2];
37848 duk__ptr_union pu;
37849
37850 DUK_ASSERT(thr != NULL);
37851 DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
37852 /* ptr may be NULL */
37853
37854 buf[0] = ibyte;
37855 buf[1] = sizeof(pu);
37856 duk_debug_write_bytes(thr, buf, 2);
37857 pu.p = (void *) ptr;
37858#if defined(DUK_USE_INTEGER_LE)
37859 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
37860#endif
37861 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
37862}
37863
37864DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) {
37865 duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER);
37866}
37867
37868#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
37869DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
37870 duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR);
37871}
37872#endif /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */
37873
37874DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
37875 duk_uint8_t buf[3];
37876 duk__ptr_union pu;
37877
37878 DUK_ASSERT(thr != NULL);
37879 DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
37880 DUK_ASSERT(obj != NULL);
37881
37882 buf[0] = DUK_DBG_IB_OBJECT;
37883 buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj);
37884 buf[2] = sizeof(pu);
37885 duk_debug_write_bytes(thr, buf, 3);
37886 pu.p = (void *) obj;
37887#if defined(DUK_USE_INTEGER_LE)
37888 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
37889#endif
37890 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
37891}
37892
37893DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
37894 duk_c_function lf_func;
37895 duk_small_uint_t lf_flags;
37896 duk_uint8_t buf[4];
37897 duk_double_union du1;
37898 duk_double_union du2;
37899 duk_int32_t i32;
37900
37901 DUK_ASSERT(thr != NULL);
37902 DUK_ASSERT(tv != NULL);
37903
37904 switch (DUK_TVAL_GET_TAG(tv)) {
37905 case DUK_TAG_UNDEFINED:
37906 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
37907 break;
37908 case DUK_TAG_UNUSED:
37909 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
37910 break;
37911 case DUK_TAG_NULL:
37912 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
37913 break;
37914 case DUK_TAG_BOOLEAN:
37915 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 ||
37916 DUK_TVAL_GET_BOOLEAN(tv) == 1);
37917 duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv));
37918 break;
37919 case DUK_TAG_POINTER:
37920 duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv));
37921 break;
37922 case DUK_TAG_LIGHTFUNC:
37923 DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
37924 buf[0] = DUK_DBG_IB_LIGHTFUNC;
37925 buf[1] = (duk_uint8_t) (lf_flags >> 8);
37926 buf[2] = (duk_uint8_t) (lf_flags & 0xff);
37927 buf[3] = sizeof(lf_func);
37928 duk_debug_write_bytes(thr, buf, 4);
37929 duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func));
37930 break;
37931 case DUK_TAG_STRING:
37932 duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv));
37933 break;
37934 case DUK_TAG_OBJECT:
37935 duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv));
37936 break;
37937 case DUK_TAG_BUFFER:
37938 duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv));
37939 break;
37940#if defined(DUK_USE_FASTINT)
37941 case DUK_TAG_FASTINT:
37942#endif
37943 default:
37944 /* Numbers are normalized to big (network) endian. We can
37945 * (but are not required) to use integer dvalues when there's
37946 * no loss of precision.
37947 *
37948 * XXX: share check with other code; this check is slow but
37949 * reliable and doesn't require careful exponent/mantissa
37950 * mask tricks as in the fastint downgrade code.
37951 */
37952 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
37953 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
37954 du1.d = DUK_TVAL_GET_NUMBER(tv);
37955 i32 = (duk_int32_t) du1.d;
37956 du2.d = (duk_double_t) i32;
37957
37958 DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x "
37959 "du2=%02x%02x%02x%02x%02x%02x%02x%02x",
37960 (long) i32,
37961 (unsigned int) du1.uc[0], (unsigned int) du1.uc[1],
37962 (unsigned int) du1.uc[2], (unsigned int) du1.uc[3],
37963 (unsigned int) du1.uc[4], (unsigned int) du1.uc[5],
37964 (unsigned int) du1.uc[6], (unsigned int) du1.uc[7],
37965 (unsigned int) du2.uc[0], (unsigned int) du2.uc[1],
37966 (unsigned int) du2.uc[2], (unsigned int) du2.uc[3],
37967 (unsigned int) du2.uc[4], (unsigned int) du2.uc[5],
37968 (unsigned int) du2.uc[6], (unsigned int) du2.uc[7]));
37969
37970 if (DUK_MEMCMP((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
37971 duk_debug_write_int(thr, i32);
37972 } else {
37973 DUK_DBLUNION_DOUBLE_HTON(&du1);
37974 duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER);
37975 duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc));
37976 }
37977 }
37978}
37979
37980#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
37981/* Variant for writing duk_tvals so that any heap allocated values are
37982 * written out as tagged heap pointers.
37983 */
37984DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) {
37985 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
37986 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
37987 duk_debug_write_heapptr(thr, h);
37988 } else {
37989 duk_debug_write_tval(thr, tv);
37990 }
37991}
37992#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
37993
37994/*
37995 * Debug connection message write helpers
37996 */
37997
37998#if 0 /* unused */
37999DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) {
38000 duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST);
38001 duk_debug_write_int(thr, command);
38002}
38003#endif
38004
38005DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) {
38006 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
38007}
38008
38009DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) {
38010 /* Allow NULL 'msg' */
38011 duk_debug_write_byte(thr, DUK_DBG_IB_ERROR);
38012 duk_debug_write_int(thr, (duk_int32_t) err_code);
38013 duk_debug_write_cstring(thr, msg);
38014 duk_debug_write_eom(thr);
38015}
38016
38017DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
38018 duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
38019 duk_debug_write_int(thr, command);
38020}
38021
38022DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
38023 duk_debug_write_byte(thr, DUK_DBG_IB_EOM);
38024
38025 /* As an initial implementation, write flush after every EOM (and the
38026 * version identifier). A better implementation would flush only when
38027 * Duktape is finished processing messages so that a flush only happens
38028 * after all outbound messages are finished on that occasion.
38029 */
38030 duk_debug_write_flush(thr);
38031}
38032
38033/*
38034 * Status message and helpers
38035 */
38036
38037DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
38038 duk_context *ctx = (duk_context *) thr;
38039 duk_activation *act;
38040 duk_uint_fast32_t line;
38041 duk_uint_fast32_t pc;
38042
38043 act = duk_hthread_get_current_activation(thr); /* may be NULL */
38044 if (act == NULL) {
38045 return 0;
38046 }
38047
38048 /* We're conceptually between two opcodes; act->pc indicates the next
38049 * instruction to be executed. This is usually the correct pc/line to
38050 * indicate in Status. (For the 'debugger' statement this now reports
38051 * the pc/line after the debugger statement because the debugger opcode
38052 * has already been executed.)
38053 */
38054
38055 pc = duk_hthread_get_act_curr_pc(thr, act);
38056
38057 /* XXX: this should be optimized to be a raw query and avoid valstack
38058 * operations if possible.
38059 */
38060 duk_push_tval(ctx, &act->tv_func);
38061 line = duk_hobject_pc2line_query(ctx, -1, pc);
38062 duk_pop(ctx);
38063 return line;
38064}
38065
38066DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
38067 duk_context *ctx = (duk_context *) thr;
38068 duk_activation *act;
38069
38070 duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
38071 duk_debug_write_int(thr, thr->heap->dbg_paused);
38072
38073 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
38074 if (thr->callstack_top == 0) {
38075 duk_debug_write_undefined(thr);
38076 duk_debug_write_undefined(thr);
38077 duk_debug_write_int(thr, 0);
38078 duk_debug_write_int(thr, 0);
38079 } else {
38080 act = thr->callstack + thr->callstack_top - 1;
38081 duk_push_tval(ctx, &act->tv_func);
38082 duk_get_prop_string(ctx, -1, "fileName");
38083 duk__debug_write_hstring_safe_top(thr);
38084 duk_get_prop_string(ctx, -2, "name");
38085 duk__debug_write_hstring_safe_top(thr);
38086 duk_pop_3(ctx);
38087 /* Report next pc/line to be executed. */
38088 duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
38089 act = thr->callstack + thr->callstack_top - 1;
38090 duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
38091 }
38092
38093 duk_debug_write_eom(thr);
38094}
38095
38096#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
38097DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
38098 /*
38099 * NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
38100 */
38101
38102 duk_context *ctx = (duk_context *) thr;
38103 duk_activation *act;
38104 duk_uint32_t pc;
38105
38106 DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */
38107
38108 duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
38109 duk_debug_write_int(thr, fatal);
38110
38111 /* Report thrown value to client coerced to string */
38112 duk_dup(ctx, -1);
38113 duk__debug_write_hstring_safe_top(thr);
38114 duk_pop(ctx);
38115
38116 if (duk_is_error(ctx, -1)) {
38117 /* Error instance, use augmented error data directly */
38118 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
38119 duk__debug_write_hstring_safe_top(thr);
38120 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER);
38121 duk_debug_write_uint(thr, duk_get_uint(ctx, -1));
38122 duk_pop_2(ctx);
38123 } else {
38124 /* For anything other than an Error instance, we calculate the
38125 * error location directly from the current activation if one
38126 * exists.
38127 */
38128 if (thr->callstack_top > 0) {
38129 act = thr->callstack + thr->callstack_top - 1;
38130 duk_push_tval(ctx, &act->tv_func);
38131 duk_get_prop_string(ctx, -1, "fileName");
38132 duk__debug_write_hstring_safe_top(thr);
38133 act = thr->callstack + thr->callstack_top - 1;
38134 pc = duk_hthread_get_act_prev_pc(thr, act);
38135 duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc));
38136 duk_pop_2(ctx);
38137 } else {
38138 /* Can happen if duk_throw() is called on an empty
38139 * callstack.
38140 */
38141 duk_debug_write_cstring(thr, "");
38142 duk_debug_write_uint(thr, 0);
38143 }
38144 }
38145
38146 duk_debug_write_eom(thr);
38147}
38148#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY */
38149
38150/*
38151 * Debug message processing
38152 */
38153
38154/* Skip dvalue. */
38155DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
38156 duk_uint8_t x;
38157 duk_uint32_t len;
38158
38159 x = duk_debug_read_byte(thr);
38160
38161 if (x >= 0xc0) {
38162 duk_debug_skip_byte(thr);
38163 return 0;
38164 }
38165 if (x >= 0x80) {
38166 return 0;
38167 }
38168 if (x >= 0x60) {
38169 duk_debug_skip_bytes(thr, x - 0x60);
38170 return 0;
38171 }
38172 switch(x) {
38173 case DUK_DBG_IB_EOM:
38174 return 1; /* Return 1: got EOM */
38175 case DUK_DBG_IB_REQUEST:
38176 case DUK_DBG_IB_REPLY:
38177 case DUK_DBG_IB_ERROR:
38178 case DUK_DBG_IB_NOTIFY:
38179 break;
38180 case DUK_DBG_IB_INT4:
38181 (void) duk__debug_read_uint32_raw(thr);
38182 break;
38183 case DUK_DBG_IB_STR4:
38184 case DUK_DBG_IB_BUF4:
38185 len = duk__debug_read_uint32_raw(thr);
38186 duk_debug_skip_bytes(thr, len);
38187 break;
38188 case DUK_DBG_IB_STR2:
38189 case DUK_DBG_IB_BUF2:
38190 len = duk__debug_read_uint16_raw(thr);
38191 duk_debug_skip_bytes(thr, len);
38192 break;
38193 case DUK_DBG_IB_UNUSED:
38194 case DUK_DBG_IB_UNDEFINED:
38195 case DUK_DBG_IB_NULL:
38196 case DUK_DBG_IB_TRUE:
38197 case DUK_DBG_IB_FALSE:
38198 break;
38199 case DUK_DBG_IB_NUMBER:
38200 duk_debug_skip_bytes(thr, 8);
38201 break;
38202 case DUK_DBG_IB_OBJECT:
38203 duk_debug_skip_byte(thr);
38204 len = duk_debug_read_byte(thr);
38205 duk_debug_skip_bytes(thr, len);
38206 break;
38207 case DUK_DBG_IB_POINTER:
38208 case DUK_DBG_IB_HEAPPTR:
38209 len = duk_debug_read_byte(thr);
38210 duk_debug_skip_bytes(thr, len);
38211 break;
38212 case DUK_DBG_IB_LIGHTFUNC:
38213 duk_debug_skip_bytes(thr, 2);
38214 len = duk_debug_read_byte(thr);
38215 duk_debug_skip_bytes(thr, len);
38216 break;
38217 default:
38218 goto fail;
38219 }
38220
38221 return 0;
38222
38223 fail:
38224 DUK__SET_CONN_BROKEN(thr, 1);
38225 return 1; /* Pretend like we got EOM */
38226}
38227
38228/* Skip dvalues to EOM. */
38229DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
38230 for (;;) {
38231 if (duk__debug_skip_dvalue(thr)) {
38232 break;
38233 }
38234 }
38235}
38236
38237/*
38238 * Simple commands
38239 */
38240
38241DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
38242 DUK_UNREF(heap);
38243 DUK_D(DUK_DPRINT("debug command Version"));
38244
38245 duk_debug_write_reply(thr);
38246 duk_debug_write_int(thr, DUK_VERSION);
38247 duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE);
38248 duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO);
38249#if defined(DUK_USE_DOUBLE_LE)
38250 duk_debug_write_int(thr, 1);
38251#elif defined(DUK_USE_DOUBLE_ME)
38252 duk_debug_write_int(thr, 2);
38253#elif defined(DUK_USE_DOUBLE_BE)
38254 duk_debug_write_int(thr, 3);
38255#else
38256 duk_debug_write_int(thr, 0);
38257#endif
38258 duk_debug_write_int(thr, (duk_int_t) sizeof(void *));
38259 duk_debug_write_eom(thr);
38260}
38261
38262DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) {
38263 DUK_UNREF(heap);
38264 DUK_D(DUK_DPRINT("debug command TriggerStatus"));
38265
38266 duk_debug_write_reply(thr);
38267 duk_debug_write_eom(thr);
38268 heap->dbg_state_dirty = 1;
38269}
38270
38271DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
38272 DUK_D(DUK_DPRINT("debug command Pause"));
38273
38274 DUK_HEAP_SET_PAUSED(heap);
38275 duk_debug_write_reply(thr);
38276 duk_debug_write_eom(thr);
38277}
38278
38279DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
38280 DUK_D(DUK_DPRINT("debug command Resume"));
38281
38282 DUK_HEAP_CLEAR_PAUSED(heap);
38283 duk_debug_write_reply(thr);
38284 duk_debug_write_eom(thr);
38285}
38286
38287DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
38288 duk_small_uint_t step_type;
38289 duk_uint_fast32_t line;
38290
38291 DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
38292
38293 if (cmd == DUK_DBG_CMD_STEPINTO) {
38294 step_type = DUK_STEP_TYPE_INTO;
38295 } else if (cmd == DUK_DBG_CMD_STEPOVER) {
38296 step_type = DUK_STEP_TYPE_OVER;
38297 } else {
38298 DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
38299 step_type = DUK_STEP_TYPE_OUT;
38300 }
38301
38302 line = duk_debug_curr_line(thr);
38303 if (line > 0) {
38304 heap->dbg_paused = 0;
38305 heap->dbg_step_type = step_type;
38306 heap->dbg_step_thread = thr;
38307 heap->dbg_step_csindex = thr->callstack_top - 1;
38308 heap->dbg_step_startline = line;
38309 heap->dbg_state_dirty = 1;
38310 } else {
38311 DUK_D(DUK_DPRINT("cannot determine current line, stepinto/stepover/stepout ignored"));
38312 }
38313 duk_debug_write_reply(thr);
38314 duk_debug_write_eom(thr);
38315}
38316
38317DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
38318 duk_small_int_t i;
38319
38320 DUK_D(DUK_DPRINT("debug command ListBreak"));
38321 duk_debug_write_reply(thr);
38322 for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) {
38323 duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename);
38324 duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line);
38325 }
38326 duk_debug_write_eom(thr);
38327}
38328
38329DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
38330 duk_hstring *filename;
38331 duk_uint32_t linenumber;
38332 duk_small_int_t idx;
38333
38334 DUK_UNREF(heap);
38335
38336 filename = duk_debug_read_hstring(thr);
38337 linenumber = (duk_uint32_t) duk_debug_read_int(thr);
38338 DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber));
38339 idx = duk_debug_add_breakpoint(thr, filename, linenumber);
38340 if (idx >= 0) {
38341 duk_debug_write_reply(thr);
38342 duk_debug_write_int(thr, (duk_int32_t) idx);
38343 duk_debug_write_eom(thr);
38344 } else {
38345 duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
38346 }
38347}
38348
38349DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
38350 duk_small_uint_t idx;
38351
38352 DUK_UNREF(heap);
38353
38354 DUK_D(DUK_DPRINT("debug command DelBreak"));
38355 idx = (duk_small_uint_t) duk_debug_read_int(thr);
38356 if (duk_debug_remove_breakpoint(thr, idx)) {
38357 duk_debug_write_reply(thr);
38358 duk_debug_write_eom(thr);
38359 } else {
38360 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index");
38361 }
38362}
38363
38364DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
38365 duk_context *ctx = (duk_context *) thr;
38366 duk_hstring *str;
38367 duk_bool_t rc;
38368 duk_int32_t level;
38369
38370 DUK_UNREF(heap);
38371 DUK_D(DUK_DPRINT("debug command GetVar"));
38372
38373 str = duk_debug_read_hstring(thr); /* push to stack */
38374 DUK_ASSERT(str != NULL);
38375 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38376 level = duk_debug_read_int(thr); /* optional callstack level */
38377 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38378 DUK_D(DUK_DPRINT("invalid callstack level for GetVar"));
38379 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38380 return;
38381 }
38382 } else {
38383 level = -1;
38384 }
38385
38386 if (thr->callstack_top > 0) {
38387 rc = duk_js_getvar_activation(thr,
38388 thr->callstack + thr->callstack_top + level,
38389 str,
38390 0);
38391 } else {
38392 /* No activation, no variable access. Could also pretend
38393 * we're in the global program context and read stuff off
38394 * the global object.
38395 */
38396 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
38397 rc = 0;
38398 }
38399
38400 duk_debug_write_reply(thr);
38401 if (rc) {
38402 duk_debug_write_int(thr, 1);
38403 DUK_ASSERT(duk_get_tval(ctx, -2) != NULL);
38404 duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
38405 } else {
38406 duk_debug_write_int(thr, 0);
38407 duk_debug_write_unused(thr);
38408 }
38409 duk_debug_write_eom(thr);
38410}
38411
38412DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
38413 duk_hstring *str;
38414 duk_tval *tv;
38415 duk_int32_t level;
38416
38417 DUK_UNREF(heap);
38418 DUK_D(DUK_DPRINT("debug command PutVar"));
38419
38420 str = duk_debug_read_hstring(thr); /* push to stack */
38421 DUK_ASSERT(str != NULL);
38422 tv = duk_debug_read_tval(thr);
38423 if (tv == NULL) {
38424 /* detached */
38425 return;
38426 }
38427 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38428 level = duk_debug_read_int(thr); /* optional callstack level */
38429 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38430 DUK_D(DUK_DPRINT("invalid callstack level for PutVar"));
38431 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38432 return;
38433 }
38434 } else {
38435 level = -1;
38436 }
38437
38438 if (thr->callstack_top > 0) {
38439 duk_js_putvar_activation(thr,
38440 thr->callstack + thr->callstack_top + level,
38441 str,
38442 tv,
38443 0);
38444 } else {
38445 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
38446 }
38447
38448 /* XXX: Current putvar implementation doesn't have a success flag,
38449 * add one and send to debug client?
38450 */
38451 duk_debug_write_reply(thr);
38452 duk_debug_write_eom(thr);
38453}
38454
38455DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
38456 duk_context *ctx = (duk_context *) thr;
38457 duk_hthread *curr_thr = thr;
38458 duk_activation *curr_act;
38459 duk_uint_fast32_t pc;
38460 duk_uint_fast32_t line;
38461 duk_size_t i;
38462
38463 DUK_ASSERT(thr != NULL);
38464 DUK_UNREF(heap);
38465
38466 duk_debug_write_reply(thr);
38467 while (curr_thr != NULL) {
38468 i = curr_thr->callstack_top;
38469 while (i > 0) {
38470 i--;
38471 curr_act = curr_thr->callstack + i;
38472
38473 /* PC/line semantics here are:
38474 * - For callstack top we're conceptually between two
38475 * opcodes and current PC indicates next line to
38476 * execute, so report that (matches Status).
38477 * - For other activations we're conceptually still
38478 * executing the instruction at PC-1, so report that
38479 * (matches error stacktrace behavior).
38480 * - See: https://github.com/svaarala/duktape/issues/281
38481 */
38482
38483 /* XXX: optimize to use direct reads, i.e. avoid
38484 * value stack operations.
38485 */
38486 duk_push_tval(ctx, &curr_act->tv_func);
38487 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
38488 duk__debug_write_hstring_safe_top(thr);
38489 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
38490 duk__debug_write_hstring_safe_top(thr);
38491 pc = duk_hthread_get_act_curr_pc(thr, curr_act);
38492 if (i != curr_thr->callstack_top - 1 && pc > 0) {
38493 pc--;
38494 }
38495 line = duk_hobject_pc2line_query(ctx, -3, pc);
38496 duk_debug_write_uint(thr, (duk_uint32_t) line);
38497 duk_debug_write_uint(thr, (duk_uint32_t) pc);
38498 duk_pop_3(ctx);
38499 }
38500 curr_thr = curr_thr->resumer;
38501 }
38502 /* SCANBUILD: warning about 'thr' potentially being NULL here,
38503 * warning is incorrect because thr != NULL always here.
38504 */
38505 duk_debug_write_eom(thr);
38506}
38507
38508DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
38509 duk_context *ctx = (duk_context *) thr;
38510 duk_activation *curr_act;
38511 duk_int32_t level;
38512 duk_hstring *varname;
38513
38514 DUK_UNREF(heap);
38515
38516 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38517 level = duk_debug_read_int(thr); /* optional callstack level */
38518 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38519 DUK_D(DUK_DPRINT("invalid callstack level for GetLocals"));
38520 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38521 return;
38522 }
38523 duk_debug_write_reply(thr);
38524 } else {
38525 duk_debug_write_reply(thr);
38526 if (thr->callstack_top == 0) {
38527 goto callstack_empty;
38528 }
38529 level = -1;
38530 }
38531
38532 curr_act = thr->callstack + thr->callstack_top + level;
38533
38534 /* XXX: several nice-to-have improvements here:
38535 * - Use direct reads avoiding value stack operations
38536 * - Avoid triggering getters, indicate getter values to debug client
38537 * - If side effects are possible, add error catching
38538 */
38539
38540 duk_push_tval(ctx, &curr_act->tv_func);
38541 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP);
38542 if (duk_is_object(ctx, -1)) {
38543 duk_enum(ctx, -1, 0 /*enum_flags*/);
38544 while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
38545 varname = duk_get_hstring(ctx, -1);
38546 DUK_ASSERT(varname != NULL);
38547
38548 duk_js_getvar_activation(thr, curr_act, varname, 0 /*throw_flag*/);
38549 /* [ ... func varmap enum key value this ] */
38550 duk_debug_write_hstring(thr, duk_get_hstring(ctx, -3));
38551 duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
38552 duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
38553 }
38554 } else {
38555 DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
38556 }
38557
38558 callstack_empty:
38559 duk_debug_write_eom(thr);
38560}
38561
38562DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
38563 duk_context *ctx = (duk_context *) thr;
38564 duk_small_uint_t call_flags;
38565 duk_int_t call_ret;
38566 duk_small_int_t eval_err;
38567 duk_int32_t level;
38568
38569 DUK_UNREF(heap);
38570
38571 DUK_D(DUK_DPRINT("debug command Eval"));
38572
38573 /* The eval code is executed within the lexical environment of a specified
38574 * activation. For now, use global object eval() function, with the eval
38575 * considered a 'direct call to eval'.
38576 *
38577 * Callstack level for debug commands only affects scope -- the callstack
38578 * as seen by, e.g. Duktape.act() will be the same regardless.
38579 */
38580
38581 /* nargs == 2 so we can pass a callstack level to eval(). */
38582 duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/);
38583 duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
38584
38585 (void) duk_debug_read_hstring(thr);
38586 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38587 level = duk_debug_read_int(thr); /* optional callstack level */
38588 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38589 DUK_D(DUK_DPRINT("invalid callstack level for Eval"));
38590 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38591 return;
38592 }
38593 }
38594 else {
38595 level = -1;
38596 }
38597 DUK_ASSERT(level < 0 && -level <= (duk_int32_t) thr->callstack_top);
38598 duk_push_int(ctx, level - 1); /* compensate for eval() call */
38599
38600 /* [ ... eval "eval" eval_input level ] */
38601
38602 call_flags = 0;
38603 if (thr->callstack_top >= (duk_size_t) -level) {
38604 duk_activation *act;
38605 duk_hobject *fun;
38606
38607 act = thr->callstack + thr->callstack_top + level;
38608 fun = DUK_ACT_GET_FUNC(act);
38609 if (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) {
38610 /* Direct eval requires that there's a current
38611 * activation and it is an Ecmascript function.
38612 * When Eval is executed from e.g. cooperate API
38613 * call we'll need to do an indirect eval instead.
38614 */
38615 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
38616 }
38617 }
38618
38619 call_ret = duk_handle_call_protected(thr, 2 /*num_stack_args*/, call_flags);
38620
38621 if (call_ret == DUK_EXEC_SUCCESS) {
38622 eval_err = 0;
38623 /* Use result value as is. */
38624 } else {
38625 /* For errors a string coerced result is most informative
38626 * right now, as the debug client doesn't have the capability
38627 * to traverse the error object.
38628 */
38629 eval_err = 1;
38630 duk_safe_to_string(ctx, -1);
38631 }
38632
38633 /* [ ... result ] */
38634
38635 duk_debug_write_reply(thr);
38636 duk_debug_write_int(thr, (duk_int32_t) eval_err);
38637 DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
38638 duk_debug_write_tval(thr, duk_get_tval(ctx, -1));
38639 duk_debug_write_eom(thr);
38640}
38641
38642DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
38643 DUK_UNREF(heap);
38644 DUK_D(DUK_DPRINT("debug command Detach"));
38645
38646 duk_debug_write_reply(thr);
38647 duk_debug_write_eom(thr);
38648
38649 DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
38650 DUK__SET_CONN_BROKEN(thr, 0); /* not an error */
38651}
38652
38653DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
38654 duk_context *ctx = (duk_context *) thr;
38655 duk_idx_t old_top;
38656
38657 DUK_D(DUK_DPRINT("debug command AppRequest"));
38658
38659 old_top = duk_get_top(ctx); /* save stack top */
38660
38661 if (heap->dbg_request_cb != NULL) {
38662 duk_idx_t nrets;
38663 duk_idx_t nvalues = 0;
38664 duk_idx_t top, idx;
38665
38666 /* Read tvals from the message and push them onto the valstack,
38667 * then call the request callback to process the request.
38668 */
38669 while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38670 duk_tval *tv;
38671 if (!duk_check_stack(ctx, 1)) {
38672 DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
38673 goto fail;
38674 }
38675 tv = duk_debug_read_tval(thr); /* push to stack */
38676 if (tv == NULL) {
38677 /* detached */
38678 return;
38679 }
38680 nvalues++;
38681 }
38682 DUK_ASSERT(duk_get_top(ctx) == old_top + nvalues);
38683
38684 /* Request callback should push values for reply to client onto valstack */
38685 DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
38686 (long) nvalues, (long) old_top, (long) duk_get_top(ctx)));
38687 nrets = heap->dbg_request_cb(ctx, heap->dbg_udata, nvalues);
38688 DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
38689 (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(ctx)));
38690 if (nrets >= 0) {
38691 DUK_ASSERT(duk_get_top(ctx) >= old_top + nrets);
38692 if (duk_get_top(ctx) < old_top + nrets) {
38693 DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
38694 "top=%ld < old_top=%ld + nrets=%ld; "
38695 "this might mean it's unsafe to continue!",
38696 (long) duk_get_top(ctx), (long) old_top, (long) nrets));
38697 goto fail;
38698 }
38699
38700 /* Reply with tvals pushed by request callback */
38701 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
38702 top = duk_get_top(ctx);
38703 for (idx = top - nrets; idx < top; idx++) {
38704 duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(ctx, idx));
38705 }
38706 duk_debug_write_eom(thr);
38707 } else {
38708 DUK_ASSERT(duk_get_top(ctx) >= old_top + 1);
38709 if (duk_get_top(ctx) < old_top + 1) {
38710 DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
38711 goto fail;
38712 }
38713 duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(ctx, -1));
38714 }
38715
38716 duk_set_top(ctx, old_top); /* restore stack top */
38717 } else {
38718 DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
38719 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
38720 }
38721
38722 return;
38723
38724 fail:
38725 duk_set_top(ctx, old_top); /* restore stack top */
38726 DUK__SET_CONN_BROKEN(thr, 1);
38727}
38728
38729/*
38730 * DumpHeap command
38731 */
38732
38733#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
38734/* XXX: this has some overlap with object inspection; remove this and make
38735 * DumpHeap return lists of heapptrs instead?
38736 */
38737DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) {
38738 DUK_UNREF(heap);
38739
38740 duk_debug_write_heapptr(thr, hdr);
38741 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr));
38742 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr));
38743#if defined(DUK_USE_REFERENCE_COUNTING)
38744 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr));
38745#else
38746 duk_debug_write_int(thr, (duk_int32_t) -1);
38747#endif
38748
38749 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
38750 case DUK_HTYPE_STRING: {
38751 duk_hstring *h = (duk_hstring *) hdr;
38752
38753 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_BYTELEN(h));
38754 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_CHARLEN(h));
38755 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_HASH(h));
38756 duk_debug_write_hstring(thr, h);
38757 break;
38758 }
38759 case DUK_HTYPE_OBJECT: {
38760 duk_hobject *h = (duk_hobject *) hdr;
38761 duk_hstring *k;
38762 duk_uint_fast32_t i;
38763
38764 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h));
38765 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
38766 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h));
38767 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h));
38768 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h));
38769 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h));
38770
38771 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
38772 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i));
38773 k = DUK_HOBJECT_E_GET_KEY(heap, h, i);
38774 duk_debug_write_heapptr(thr, (duk_heaphdr *) k);
38775 if (k == NULL) {
38776 duk_debug_write_int(thr, 0); /* isAccessor */
38777 duk_debug_write_unused(thr);
38778 continue;
38779 }
38780 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
38781 duk_debug_write_int(thr, 1); /* isAccessor */
38782 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
38783 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
38784 } else {
38785 duk_debug_write_int(thr, 0); /* isAccessor */
38786
38787 duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
38788 }
38789 }
38790
38791 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
38792 /* Note: array dump will include elements beyond
38793 * 'length'.
38794 */
38795 duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
38796 }
38797 break;
38798 }
38799 case DUK_HTYPE_BUFFER: {
38800 duk_hbuffer *h = (duk_hbuffer *) hdr;
38801
38802 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h));
38803 duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
38804 break;
38805 }
38806 default: {
38807 DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr)));
38808 }
38809 }
38810}
38811
38812DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) {
38813 duk_heaphdr *hdr;
38814
38815 hdr = heap->heap_allocated;
38816 while (hdr != NULL) {
38817 duk__debug_dump_heaphdr(thr, heap, hdr);
38818 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
38819 }
38820}
38821
38822#if defined(DUK_USE_STRTAB_CHAIN)
38823DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) {
38824 duk_uint_fast32_t i, j;
38825 duk_strtab_entry *e;
38826#if defined(DUK_USE_HEAPPTR16)
38827 duk_uint16_t *lst;
38828#else
38829 duk_hstring **lst;
38830#endif
38831 duk_hstring *h;
38832
38833 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
38834 e = heap->strtable + i;
38835 if (e->listlen > 0) {
38836#if defined(DUK_USE_HEAPPTR16)
38837 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
38838#else
38839 lst = e->u.strlist;
38840#endif
38841 DUK_ASSERT(lst != NULL);
38842
38843 for (j = 0; j < e->listlen; j++) {
38844#if defined(DUK_USE_HEAPPTR16)
38845 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
38846#else
38847 h = lst[j];
38848#endif
38849 if (h != NULL) {
38850 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
38851 }
38852 }
38853 } else {
38854#if defined(DUK_USE_HEAPPTR16)
38855 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
38856#else
38857 h = e->u.str;
38858#endif
38859 if (h != NULL) {
38860 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
38861 }
38862 }
38863 }
38864}
38865#endif /* DUK_USE_STRTAB_CHAIN */
38866
38867#if defined(DUK_USE_STRTAB_PROBE)
38868DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) {
38869 duk_uint32_t i;
38870 duk_hstring *h;
38871
38872 for (i = 0; i < heap->st_size; i++) {
38873#if defined(DUK_USE_HEAPPTR16)
38874 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
38875#else
38876 h = heap->strtable[i];
38877#endif
38878 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
38879 continue;
38880 }
38881
38882 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
38883 }
38884}
38885#endif /* DUK_USE_STRTAB_PROBE */
38886
38887DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
38888 DUK_D(DUK_DPRINT("debug command DumpHeap"));
38889
38890 duk_debug_write_reply(thr);
38891 duk__debug_dump_heap_allocated(thr, heap);
38892#if defined(DUK_USE_STRTAB_CHAIN)
38893 duk__debug_dump_strtab_chain(thr, heap);
38894#endif
38895#if defined(DUK_USE_STRTAB_PROBE)
38896 duk__debug_dump_strtab_probe(thr, heap);
38897#endif
38898 duk_debug_write_eom(thr);
38899}
38900#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
38901
38902DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
38903 duk_activation *act;
38904 duk_hcompiledfunction *fun = NULL;
38905 duk_size_t i, n;
38906 duk_tval *tv;
38907 duk_hobject **fn;
38908 duk_int32_t level = -1;
38909 duk_uint8_t ibyte;
38910
38911 DUK_UNREF(heap);
38912
38913 DUK_D(DUK_DPRINT("debug command GetBytecode"));
38914
38915 ibyte = duk_debug_peek_byte(thr);
38916 if (ibyte != DUK_DBG_IB_EOM) {
38917 tv = duk_debug_read_tval(thr);
38918 if (tv == NULL) {
38919 /* detached */
38920 return;
38921 }
38922 if (DUK_TVAL_IS_OBJECT(tv)) {
38923 /* tentative, checked later */
38924 fun = (duk_hcompiledfunction *) DUK_TVAL_GET_OBJECT(tv);
38925 DUK_ASSERT(fun != NULL);
38926 } else if (DUK_TVAL_IS_NUMBER(tv)) {
38927 level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv);
38928 } else {
38929 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T", tv));
38930 goto fail_args;
38931 }
38932 }
38933
38934 if (fun == NULL) {
38935 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38936 DUK_D(DUK_DPRINT("invalid callstack level for GetBytecode"));
38937 goto fail_level;
38938 }
38939 act = thr->callstack + thr->callstack_top + level;
38940 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
38941 }
38942
38943 if (fun == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)) {
38944 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun));
38945 goto fail_args;
38946 }
38947 DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun));
38948
38949 duk_debug_write_reply(thr);
38950 n = DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap, fun);
38951 duk_debug_write_int(thr, (duk_int32_t) n);
38952 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, fun);
38953 for (i = 0; i < n; i++) {
38954 duk_debug_write_tval(thr, tv);
38955 tv++;
38956 }
38957 n = DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap, fun);
38958 duk_debug_write_int(thr, (duk_int32_t) n);
38959 fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, fun);
38960 for (i = 0; i < n; i++) {
38961 duk_debug_write_hobject(thr, *fn);
38962 fn++;
38963 }
38964 duk_debug_write_string(thr,
38965 (const char *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap, fun),
38966 (duk_size_t) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap, fun));
38967 duk_debug_write_eom(thr);
38968 return;
38969
38970 fail_args:
38971 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument");
38972 return;
38973
38974 fail_level:
38975 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38976 return;
38977}
38978
38979/*
38980 * Object inspection commands: GetHeapObjInfo, GetObjPropDesc,
38981 * GetObjPropDescRange
38982 */
38983
38984#if defined(DUK_USE_DEBUGGER_INSPECT)
38985
38986#if 0 /* pruned */
38987DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = {
38988 "reachable",
38989 "temproot",
38990 "finalizable",
38991 "finalized",
38992 "readonly"
38993 /* NULL not needed here */
38994};
38995DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = {
38996 DUK_HEAPHDR_FLAG_REACHABLE,
38997 DUK_HEAPHDR_FLAG_TEMPROOT,
38998 DUK_HEAPHDR_FLAG_FINALIZABLE,
38999 DUK_HEAPHDR_FLAG_FINALIZED,
39000 DUK_HEAPHDR_FLAG_READONLY,
39001 0 /* terminator */
39002};
39003#endif
39004DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
39005#if 0
39006 "arridx",
39007 "internal",
39008 "reserved_word",
39009 "strict_reserved_word",
39010 "eval_or_arguments",
39011#endif
39012 "extdata"
39013 /* NULL not needed here */
39014};
39015DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
39016#if 0
39017 DUK_HSTRING_FLAG_ARRIDX,
39018 DUK_HSTRING_FLAG_INTERNAL,
39019 DUK_HSTRING_FLAG_RESERVED_WORD,
39020 DUK_HSTRING_FLAG_STRICT_RESERVED_WORD,
39021 DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS,
39022#endif
39023 DUK_HSTRING_FLAG_EXTDATA,
39024 0 /* terminator */
39025};
39026DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
39027 "extensible",
39028 "constructable",
39029 "bound",
39030 "compiledfunction",
39031 "nativefunction",
39032 "bufferobject",
39033 "thread",
39034 "array_part",
39035 "strict",
39036 "notail",
39037 "newenv",
39038 "namebinding",
39039 "createargs",
39040 "envrecclosed",
39041 "exotic_array",
39042 "exotic_stringobj",
39043 "exotic_arguments",
39044 "exotic_dukfunc",
39045 "exotic_proxyobj"
39046 /* NULL not needed here */
39047};
39048DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
39049 DUK_HOBJECT_FLAG_EXTENSIBLE,
39050 DUK_HOBJECT_FLAG_CONSTRUCTABLE,
39051 DUK_HOBJECT_FLAG_BOUND,
39052 DUK_HOBJECT_FLAG_COMPILEDFUNCTION,
39053 DUK_HOBJECT_FLAG_NATIVEFUNCTION,
39054 DUK_HOBJECT_FLAG_BUFFEROBJECT,
39055 DUK_HOBJECT_FLAG_THREAD,
39056 DUK_HOBJECT_FLAG_ARRAY_PART,
39057 DUK_HOBJECT_FLAG_STRICT,
39058 DUK_HOBJECT_FLAG_NOTAIL,
39059 DUK_HOBJECT_FLAG_NEWENV,
39060 DUK_HOBJECT_FLAG_NAMEBINDING,
39061 DUK_HOBJECT_FLAG_CREATEARGS,
39062 DUK_HOBJECT_FLAG_ENVRECCLOSED,
39063 DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
39064 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
39065 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
39066 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC,
39067 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
39068 0 /* terminator */
39069};
39070DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
39071 "dynamic",
39072 "external"
39073 /* NULL not needed here */
39074};
39075DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = {
39076 DUK_HBUFFER_FLAG_DYNAMIC,
39077 DUK_HBUFFER_FLAG_EXTERNAL,
39078 0 /* terminator */
39079};
39080
39081DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) {
39082 duk_debug_write_uint(thr, 0);
39083 duk_debug_write_cstring(thr, key);
39084}
39085
39086DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) {
39087 duk_debug_write_uint(thr, 0);
39088 duk_debug_write_cstring(thr, key);
39089 duk_debug_write_uint(thr, val);
39090}
39091
39092DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) {
39093 duk_debug_write_uint(thr, 0);
39094 duk_debug_write_cstring(thr, key);
39095 duk_debug_write_int(thr, val);
39096}
39097
39098DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) {
39099 duk_debug_write_uint(thr, 0);
39100 duk_debug_write_cstring(thr, key);
39101 duk_debug_write_boolean(thr, val);
39102}
39103
39104DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) {
39105 const char *key;
39106 duk_uint_t mask;
39107
39108 for (;;) {
39109 mask = *masks++;
39110 if (!mask) {
39111 break;
39112 }
39113 key = *keys++;
39114 DUK_ASSERT(key != NULL);
39115
39116 DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx", key, (unsigned long) mask, (unsigned long) flags));
39117 duk__debug_getinfo_prop_bool(thr, key, flags & mask);
39118 }
39119}
39120
39121/* Inspect a property using a virtual index into a conceptual property list
39122 * consisting of (1) all array part items from [0,a_size[ (even when above
39123 * .length) and (2) all entry part items from [0,e_next[. Unused slots are
39124 * indicated using dvalue 'unused'.
39125 */
39126DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) {
39127 duk_uint_t a_size;
39128 duk_tval *tv;
39129 duk_hstring *h_key;
39130 duk_hobject *h_getset;
39131 duk_uint_t flags;
39132
39133 DUK_UNREF(heap);
39134
39135 a_size = DUK_HOBJECT_GET_ASIZE(h_obj);
39136 if (idx < a_size) {
39137 duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC);
39138 duk_debug_write_uint(thr, idx);
39139 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx);
39140 duk_debug_write_tval(thr, tv);
39141 return 1;
39142 }
39143
39144 idx -= a_size;
39145 if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) {
39146 return 0;
39147 }
39148
39149 h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx);
39150 if (h_key == NULL) {
39151 duk_debug_write_uint(thr, 0);
39152 duk_debug_write_null(thr);
39153 duk_debug_write_unused(thr);
39154 return 1;
39155 }
39156
39157 flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx);
39158 if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
39159 flags |= DUK_DBG_PROPFLAG_INTERNAL;
39160 }
39161 duk_debug_write_uint(thr, flags);
39162 duk_debug_write_hstring(thr, h_key);
39163 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
39164 h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx);
39165 if (h_getset) {
39166 duk_debug_write_hobject(thr, h_getset);
39167 } else {
39168 duk_debug_write_null(thr);
39169 }
39170 h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx);
39171 if (h_getset) {
39172 duk_debug_write_hobject(thr, h_getset);
39173 } else {
39174 duk_debug_write_null(thr);
39175 }
39176 } else {
39177 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx);
39178 duk_debug_write_tval(thr, tv);
39179 }
39180 return 1;
39181}
39182
39183DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) {
39184 duk_heaphdr *h;
39185
39186 DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
39187 DUK_UNREF(heap);
39188
39189 h = duk_debug_read_any_ptr(thr);
39190 if (!h) {
39191 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
39192 return;
39193 }
39194
39195 duk_debug_write_reply(thr);
39196
39197 /* As with all inspection code, we rely on the debug client providing
39198 * a valid, non-stale pointer: there's no portable way to safely
39199 * validate the pointer here.
39200 */
39201
39202 duk__debug_getinfo_flags_key(thr, "heapptr");
39203 duk_debug_write_heapptr(thr, h);
39204
39205 /* XXX: comes out as signed now */
39206 duk__debug_getinfo_prop_uint(thr, "heaphdr_flags", (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
39207 duk__debug_getinfo_prop_uint(thr, "heaphdr_type", (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h));
39208#if defined(DUK_USE_REFERENCE_COUNTING)
39209 duk__debug_getinfo_prop_uint(thr, "refcount", (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h));
39210#endif
39211#if 0 /* pruned */
39212 duk__debug_getinfo_bitmask(thr,
39213 duk__debug_getinfo_heaphdr_keys,
39214 duk__debug_getinfo_heaphdr_masks,
39215 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39216#endif
39217
39218 switch (DUK_HEAPHDR_GET_TYPE(h)) {
39219 case DUK_HTYPE_STRING: {
39220 duk_hstring *h_str;
39221
39222 h_str = (duk_hstring *) h;
39223 duk__debug_getinfo_bitmask(thr,
39224 duk__debug_getinfo_hstring_keys,
39225 duk__debug_getinfo_hstring_masks,
39226 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39227 duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str));
39228 duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str));
39229 duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str));
39230 duk__debug_getinfo_flags_key(thr, "data");
39231 duk_debug_write_hstring(thr, h_str);
39232 break;
39233 }
39234 case DUK_HTYPE_OBJECT: {
39235 duk_hobject *h_obj;
39236 duk_hobject *h_proto;
39237
39238 h_obj = (duk_hobject *) h;
39239 h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj);
39240
39241 /* duk_hobject specific fields. */
39242 duk__debug_getinfo_bitmask(thr,
39243 duk__debug_getinfo_hobject_keys,
39244 duk__debug_getinfo_hobject_masks,
39245 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39246 duk__debug_getinfo_prop_uint(thr, "class_number", DUK_HOBJECT_GET_CLASS_NUMBER(h_obj));
39247 duk__debug_getinfo_flags_key(thr, "class_name");
39248 duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj));
39249 duk__debug_getinfo_flags_key(thr, "prototype");
39250 if (h_proto != NULL) {
39251 duk_debug_write_hobject(thr, h_proto);
39252 } else {
39253 duk_debug_write_null(thr);
39254 }
39255 duk__debug_getinfo_flags_key(thr, "props");
39256 duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj));
39257 duk__debug_getinfo_prop_uint(thr, "e_size", (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
39258 duk__debug_getinfo_prop_uint(thr, "e_next", (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
39259 duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
39260 duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
39261
39262 /* duk_hnativefunction specific fields. */
39263 if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
39264 duk_hnativefunction *h_fun;
39265 h_fun = (duk_hnativefunction *) h_obj;
39266
39267 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
39268 duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic);
39269 duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATIVEFUNCTION_NARGS_VARARGS);
39270 /* Native function pointer may be different from a void pointer,
39271 * and we serialize it from memory directly now (no byte swapping etc).
39272 */
39273 duk__debug_getinfo_flags_key(thr, "funcptr");
39274 duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func));
39275 }
39276
39277 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
39278 duk_hcompiledfunction *h_fun;
39279 duk_hbuffer *h_buf;
39280 h_fun = (duk_hcompiledfunction *) h_obj;
39281
39282 duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs);
39283 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
39284 duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line);
39285 duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line);
39286 h_buf = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun);
39287 if (h_buf != NULL) {
39288 duk__debug_getinfo_flags_key(thr, "data");
39289 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf);
39290 }
39291 }
39292
39293 if (DUK_HOBJECT_IS_THREAD(h_obj)) {
39294 /* XXX: Currently no inspection of threads, e.g. value stack, call
39295 * stack, catch stack, etc.
39296 */
39297 duk_hthread *h_thr;
39298 h_thr = (duk_hthread *) h_obj;
39299 DUK_UNREF(h_thr);
39300 }
39301
39302 if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
39303 duk_hbufferobject *h_bufobj;
39304 h_bufobj = (duk_hbufferobject *) h_obj;
39305
39306 duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset);
39307 duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length);
39308 duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift);
39309 duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type);
39310 duk__debug_getinfo_prop_bool(thr, "is_view", (duk_uint_t) h_bufobj->is_view);
39311 if (h_bufobj->buf != NULL) {
39312 duk__debug_getinfo_flags_key(thr, "buffer");
39313 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf);
39314 }
39315 }
39316 break;
39317 }
39318 case DUK_HTYPE_BUFFER: {
39319 duk_hbuffer *h_buf;
39320
39321 h_buf = (duk_hbuffer *) h;
39322 duk__debug_getinfo_bitmask(thr,
39323 duk__debug_getinfo_hbuffer_keys,
39324 duk__debug_getinfo_hbuffer_masks,
39325 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39326 duk__debug_getinfo_prop_uint(thr, "size", (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
39327 duk__debug_getinfo_flags_key(thr, "dataptr");
39328 duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf));
39329 duk__debug_getinfo_flags_key(thr, "data");
39330 duk_debug_write_hbuffer(thr, h_buf); /* tolerates NULL h_buf */
39331 break;
39332 }
39333 default: {
39334 /* Since we already started writing the reply, just emit nothing. */
39335 DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type"));
39336 }
39337 }
39338
39339 duk_debug_write_eom(thr);
39340}
39341
39342DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) {
39343 duk_heaphdr *h;
39344 duk_hobject *h_obj;
39345 duk_hstring *h_key;
39346 duk_propdesc desc;
39347
39348 DUK_D(DUK_DPRINT("debug command GetObjPropDesc"));
39349 DUK_UNREF(heap);
39350
39351 h = duk_debug_read_any_ptr(thr);
39352 if (!h) {
39353 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
39354 return;
39355 }
39356 h_key = duk_debug_read_hstring(thr);
39357 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) {
39358 goto fail_args;
39359 }
39360 h_obj = (duk_hobject *) h;
39361
39362 if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) {
39363 duk_int_t virtual_idx;
39364 duk_bool_t rc;
39365
39366 /* To use the shared helper need the virtual index. */
39367 DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0);
39368 virtual_idx = (desc.a_idx >= 0 ? desc.a_idx :
39369 (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx);
39370
39371 duk_debug_write_reply(thr);
39372 rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx);
39373 DUK_ASSERT(rc == 1);
39374 DUK_UNREF(rc);
39375 duk_debug_write_eom(thr);
39376 } else {
39377 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found");
39378 }
39379 return;
39380
39381 fail_args:
39382 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
39383}
39384
39385DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) {
39386 duk_heaphdr *h;
39387 duk_hobject *h_obj;
39388 duk_uint_t idx, idx_start, idx_end;
39389
39390 DUK_D(DUK_DPRINT("debug command GetObjPropDescRange"));
39391 DUK_UNREF(heap);
39392
39393 h = duk_debug_read_any_ptr(thr);
39394 idx_start = duk_debug_read_int(thr);
39395 idx_end = duk_debug_read_int(thr);
39396 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
39397 goto fail_args;
39398 }
39399 h_obj = (duk_hobject *) h;
39400
39401 /* The index range space is conceptually the array part followed by the
39402 * entry part. Unlike normal enumeration all slots are exposed here as
39403 * is and return 'unused' if the slots are not in active use. In particular
39404 * the array part is included for the full a_size regardless of what the
39405 * array .length is.
39406 */
39407
39408 duk_debug_write_reply(thr);
39409 for (idx = idx_start; idx < idx_end; idx++) {
39410 if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) {
39411 break;
39412 }
39413 }
39414 duk_debug_write_eom(thr);
39415 return;
39416
39417 fail_args:
39418 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
39419}
39420
39421#endif /* DUK_USE_DEBUGGER_INSPECT */
39422
39423/*
39424 * Process incoming debug requests
39425 *
39426 * Individual request handlers can push temporaries on the value stack and
39427 * rely on duk__debug_process_message() to restore the value stack top
39428 * automatically.
39429 */
39430
39431/* Process one debug message. Automatically restore value stack top to its
39432 * entry value, so that individual message handlers don't need exact value
39433 * stack handling which is convenient.
39434 */
39435DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
39436 duk_context *ctx = (duk_context *) thr;
39437 duk_heap *heap;
39438 duk_uint8_t x;
39439 duk_int32_t cmd;
39440 duk_idx_t entry_top;
39441
39442 DUK_ASSERT(thr != NULL);
39443 heap = thr->heap;
39444 DUK_ASSERT(heap != NULL);
39445 DUK_UNREF(ctx);
39446
39447 entry_top = duk_get_top(ctx);
39448
39449 x = duk_debug_read_byte(thr);
39450 switch (x) {
39451 case DUK_DBG_IB_REQUEST: {
39452 cmd = duk_debug_read_int(thr);
39453 switch (cmd) {
39454 case DUK_DBG_CMD_BASICINFO: {
39455 duk__debug_handle_basic_info(thr, heap);
39456 break;
39457 }
39458 case DUK_DBG_CMD_TRIGGERSTATUS: {
39459 duk__debug_handle_trigger_status(thr, heap);
39460 break;
39461 }
39462 case DUK_DBG_CMD_PAUSE: {
39463 duk__debug_handle_pause(thr, heap);
39464 break;
39465 }
39466 case DUK_DBG_CMD_RESUME: {
39467 duk__debug_handle_resume(thr, heap);
39468 break;
39469 }
39470 case DUK_DBG_CMD_STEPINTO:
39471 case DUK_DBG_CMD_STEPOVER:
39472 case DUK_DBG_CMD_STEPOUT: {
39473 duk__debug_handle_step(thr, heap, cmd);
39474 break;
39475 }
39476 case DUK_DBG_CMD_LISTBREAK: {
39477 duk__debug_handle_list_break(thr, heap);
39478 break;
39479 }
39480 case DUK_DBG_CMD_ADDBREAK: {
39481 duk__debug_handle_add_break(thr, heap);
39482 break;
39483 }
39484 case DUK_DBG_CMD_DELBREAK: {
39485 duk__debug_handle_del_break(thr, heap);
39486 break;
39487 }
39488 case DUK_DBG_CMD_GETVAR: {
39489 duk__debug_handle_get_var(thr, heap);
39490 break;
39491 }
39492 case DUK_DBG_CMD_PUTVAR: {
39493 duk__debug_handle_put_var(thr, heap);
39494 break;
39495 }
39496 case DUK_DBG_CMD_GETCALLSTACK: {
39497 duk__debug_handle_get_call_stack(thr, heap);
39498 break;
39499 }
39500 case DUK_DBG_CMD_GETLOCALS: {
39501 duk__debug_handle_get_locals(thr, heap);
39502 break;
39503 }
39504 case DUK_DBG_CMD_EVAL: {
39505 duk__debug_handle_eval(thr, heap);
39506 break;
39507 }
39508 case DUK_DBG_CMD_DETACH: {
39509 /* The actual detached_cb call is postponed to message loop so
39510 * we don't need any special precautions here (just skip to EOM
39511 * on the already closed connection).
39512 */
39513 duk__debug_handle_detach(thr, heap);
39514 break;
39515 }
39516#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
39517 case DUK_DBG_CMD_DUMPHEAP: {
39518 duk__debug_handle_dump_heap(thr, heap);
39519 break;
39520 }
39521#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
39522 case DUK_DBG_CMD_GETBYTECODE: {
39523 duk__debug_handle_get_bytecode(thr, heap);
39524 break;
39525 }
39526 case DUK_DBG_CMD_APPREQUEST: {
39527 duk__debug_handle_apprequest(thr, heap);
39528 break;
39529 }
39530#if defined(DUK_USE_DEBUGGER_INSPECT)
39531 case DUK_DBG_CMD_GETHEAPOBJINFO: {
39532 duk__debug_handle_get_heap_obj_info(thr, heap);
39533 break;
39534 }
39535 case DUK_DBG_CMD_GETOBJPROPDESC: {
39536 duk__debug_handle_get_obj_prop_desc(thr, heap);
39537 break;
39538 }
39539 case DUK_DBG_CMD_GETOBJPROPDESCRANGE: {
39540 duk__debug_handle_get_obj_prop_desc_range(thr, heap);
39541 break;
39542 }
39543#endif /* DUK_USE_DEBUGGER_INSPECT */
39544 default: {
39545 DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd));
39546 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command");
39547 }
39548 } /* switch cmd */
39549 break;
39550 }
39551 case DUK_DBG_IB_REPLY: {
39552 DUK_D(DUK_DPRINT("debug reply, skipping"));
39553 break;
39554 }
39555 case DUK_DBG_IB_ERROR: {
39556 DUK_D(DUK_DPRINT("debug error, skipping"));
39557 break;
39558 }
39559 case DUK_DBG_IB_NOTIFY: {
39560 DUK_D(DUK_DPRINT("debug notify, skipping"));
39561 break;
39562 }
39563 default: {
39564 DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
39565 goto fail;
39566 }
39567 } /* switch initial byte */
39568
39569 DUK_ASSERT(duk_get_top(ctx) >= entry_top);
39570 duk_set_top(ctx, entry_top);
39571 duk__debug_skip_to_eom(thr);
39572 return;
39573
39574 fail:
39575 DUK_ASSERT(duk_get_top(ctx) >= entry_top);
39576 duk_set_top(ctx, entry_top);
39577 DUK__SET_CONN_BROKEN(thr, 1);
39578 return;
39579}
39580
39581DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
39582 if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) {
39583 duk_debug_send_status(thr);
39584 thr->heap->dbg_state_dirty = 0;
39585 }
39586}
39587
39588DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
39589 duk_context *ctx = (duk_context *) thr;
39590#if defined(DUK_USE_ASSERTIONS)
39591 duk_idx_t entry_top;
39592#endif
39593 duk_bool_t retval = 0;
39594
39595 DUK_ASSERT(thr != NULL);
39596 DUK_UNREF(ctx);
39597 DUK_ASSERT(thr->heap != NULL);
39598#if defined(DUK_USE_ASSERTIONS)
39599 entry_top = duk_get_top(ctx);
39600#endif
39601
39602 DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
39603 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
39604 (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
39605 DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(ctx)));
39606
39607 /* thr->heap->dbg_detaching may be != 0 if a debugger write outside
39608 * the message loop caused a transport error and detach1() to run.
39609 */
39610 DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1);
39611 DUK_ASSERT(thr->heap->dbg_processing == 0);
39612 thr->heap->dbg_processing = 1;
39613
39614 /* Ensure dirty state causes a Status even if never process any
39615 * messages. This is expected by the bytecode executor when in
39616 * the running state.
39617 */
39618 duk__check_resend_status(thr);
39619
39620 for (;;) {
39621 /* Process messages until we're no longer paused or we peek
39622 * and see there's nothing to read right now.
39623 */
39624 DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(ctx)));
39625 DUK_ASSERT(thr->heap->dbg_processing == 1);
39626
39627 while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
39628 /* Detach is pending; can be triggered from outside the
39629 * debugger loop (e.g. Status notify write error) or by
39630 * previous message handling. Call detached callback
39631 * here, in a controlled state, to ensure a possible
39632 * reattach inside the detached_cb is handled correctly.
39633 *
39634 * Recheck for detach in a while loop: an immediate
39635 * reattach involves a call to duk_debugger_attach()
39636 * which writes a debugger handshake line immediately
39637 * inside the API call. If the transport write fails
39638 * for that handshake, we can immediately end up in a
39639 * "transport broken, detaching" case several times here.
39640 * Loop back until we're either cleanly attached or
39641 * fully detached.
39642 *
39643 * NOTE: Reset dbg_processing = 1 forcibly, in case we
39644 * re-attached; duk_debugger_attach() sets dbg_processing
39645 * to 0 at the moment.
39646 */
39647
39648 DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2"));
39649
39650 duk__debug_do_detach2(thr->heap);
39651 thr->heap->dbg_processing = 1; /* may be set to 0 by duk_debugger_attach() inside callback */
39652
39653 DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld",
39654 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) thr->heap->dbg_detaching));
39655 }
39656 DUK_ASSERT(thr->heap->dbg_detaching == 0); /* true even with reattach */
39657 DUK_ASSERT(thr->heap->dbg_processing == 1); /* even after a detach and possible reattach */
39658
39659 if (thr->heap->dbg_read_cb == NULL) {
39660 DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages"));
39661 break;
39662 }
39663
39664 if (!thr->heap->dbg_paused || no_block) {
39665 if (!duk_debug_read_peek(thr)) {
39666 /* Note: peek cannot currently trigger a detach
39667 * so the dbg_detaching == 0 assert outside the
39668 * loop is correct.
39669 */
39670 DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages"));
39671 break;
39672 }
39673 DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
39674 } else {
39675 DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
39676 }
39677
39678 duk__check_resend_status(thr);
39679 duk__debug_process_message(thr);
39680 duk__check_resend_status(thr);
39681
39682 retval = 1; /* processed one or more messages */
39683 }
39684
39685 DUK_ASSERT(thr->heap->dbg_detaching == 0);
39686 DUK_ASSERT(thr->heap->dbg_processing == 1);
39687 thr->heap->dbg_processing = 0;
39688
39689 /* As an initial implementation, read flush after exiting the message
39690 * loop. If transport is broken, this is a no-op (with debug logs).
39691 */
39692 duk_debug_read_flush(thr); /* this cannot initiate a detach */
39693 DUK_ASSERT(thr->heap->dbg_detaching == 0);
39694
39695 DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(ctx)));
39696
39697#if defined(DUK_USE_ASSERTIONS)
39698 /* Easy to get wrong, so assert for it. */
39699 DUK_ASSERT(entry_top == duk_get_top(ctx));
39700#endif
39701
39702 return retval;
39703}
39704
39705/*
39706 * Halt execution helper
39707 */
39708
39709/* Halt execution and enter a debugger message loop until execution is resumed
39710 * by the client. PC for the current activation may be temporarily decremented
39711 * so that the "current" instruction will be shown by the client. This helper
39712 * is callable from anywhere, also outside bytecode executor.
39713 */
39714
39715DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) {
39716 duk_activation *act;
39717 duk_hcompiledfunction *fun;
39718 duk_instr_t *old_pc = NULL;
39719
39720 DUK_ASSERT(thr != NULL);
39721 DUK_ASSERT(thr->heap != NULL);
39722 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
39723 DUK_ASSERT(thr->heap->dbg_processing == 0);
39724
39725 DUK_HEAP_SET_PAUSED(thr->heap);
39726
39727 act = duk_hthread_get_current_activation(thr);
39728
39729 /* NOTE: act may be NULL if an error is thrown outside of any activation,
39730 * which may happen in the case of, e.g. syntax errors.
39731 */
39732
39733 /* Decrement PC if that was requested, this requires a PC sync. */
39734 if (act != NULL) {
39735 duk_hthread_sync_currpc(thr);
39736 old_pc = act->curr_pc;
39737 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
39738
39739 /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
39740 * guaranteed to be a non-NULL Ecmascript function.
39741 */
39742 DUK_ASSERT(act->curr_pc == NULL ||
39743 (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)));
39744 if (use_prev_pc &&
39745 act->curr_pc != NULL &&
39746 act->curr_pc > DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, fun)) {
39747 act->curr_pc--;
39748 }
39749 }
39750
39751 /* Process debug messages until we are no longer paused. */
39752
39753 /* NOTE: This is a bit fragile. It's important to ensure that
39754 * duk_debug_process_messages() never throws an error or
39755 * act->curr_pc will never be reset.
39756 */
39757
39758 thr->heap->dbg_state_dirty = 1;
39759 while (thr->heap->dbg_paused) {
39760 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
39761 DUK_ASSERT(thr->heap->dbg_processing);
39762 duk_debug_process_messages(thr, 0 /*no_block*/);
39763 }
39764
39765 /* XXX: Decrementing and restoring act->curr_pc works now, but if the
39766 * debugger message loop gains the ability to adjust the current PC
39767 * (e.g. a forced jump) restoring the PC here will break. Another
39768 * approach would be to use a state flag for the "decrement 1 from
39769 * topmost activation's PC" and take it into account whenever dealing
39770 * with PC values.
39771 */
39772 if (act != NULL) {
39773 act->curr_pc = old_pc; /* restore PC */
39774 }
39775}
39776
39777/*
39778 * Breakpoint management
39779 */
39780
39781DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) {
39782 duk_heap *heap;
39783 duk_breakpoint *b;
39784
39785 /* Caller must trigger recomputation of active breakpoint list. To
39786 * ensure stale values are not used if that doesn't happen, clear the
39787 * active breakpoint list here.
39788 */
39789
39790 DUK_ASSERT(thr != NULL);
39791 DUK_ASSERT(filename != NULL);
39792 heap = thr->heap;
39793 DUK_ASSERT(heap != NULL);
39794
39795 if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) {
39796 DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used",
39797 (duk_heaphdr *) filename, (long) line));
39798 return -1;
39799 }
39800 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
39801 b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++);
39802 b->filename = filename;
39803 b->line = line;
39804 DUK_HSTRING_INCREF(thr, filename);
39805
39806 return heap->dbg_breakpoint_count - 1; /* index */
39807}
39808
39809DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
39810 duk_heap *heap;
39811 duk_hstring *h;
39812 duk_breakpoint *b;
39813 duk_size_t move_size;
39814
39815 /* Caller must trigger recomputation of active breakpoint list. To
39816 * ensure stale values are not used if that doesn't happen, clear the
39817 * active breakpoint list here.
39818 */
39819
39820 DUK_ASSERT(thr != NULL);
39821 heap = thr->heap;
39822 DUK_ASSERT(heap != NULL);
39823 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
39824 DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */
39825
39826 if (breakpoint_index >= heap->dbg_breakpoint_count) {
39827 DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index));
39828 return 0;
39829 }
39830 b = heap->dbg_breakpoints + breakpoint_index;
39831
39832 h = b->filename;
39833 DUK_ASSERT(h != NULL);
39834
39835 move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
39836 if (move_size > 0) {
39837 DUK_MEMMOVE((void *) b,
39838 (const void *) (b + 1),
39839 (size_t) move_size);
39840 }
39841 heap->dbg_breakpoint_count--;
39842 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
39843
39844 DUK_HSTRING_DECREF(thr, h); /* side effects */
39845 DUK_UNREF(h); /* w/o refcounting */
39846
39847 /* Breakpoint entries above the used area are left as garbage. */
39848
39849 return 1;
39850}
39851
39852#undef DUK__SET_CONN_BROKEN
39853
39854#else /* DUK_USE_DEBUGGER_SUPPORT */
39855
39856/* No debugger support. */
39857
39858#endif /* DUK_USE_DEBUGGER_SUPPORT */
39859#line 1 "duk_error_augment.c"
39860/*
39861 * Augmenting errors at their creation site and their throw site.
39862 *
39863 * When errors are created, traceback data is added by built-in code
39864 * and a user error handler (if defined) can process or replace the
39865 * error. Similarly, when errors are thrown, a user error handler
39866 * (if defined) can process or replace the error.
39867 *
39868 * Augmentation and other processing at error creation time is nice
39869 * because an error is only created once, but it may be thrown and
39870 * rethrown multiple times. User error handler registered for processing
39871 * an error at its throw site must be careful to handle rethrowing in
39872 * a useful manner.
39873 *
39874 * Error augmentation may throw an internal error (e.g. alloc error).
39875 *
39876 * Ecmascript allows throwing any values, so all values cannot be
39877 * augmented. Currently, the built-in augmentation at error creation
39878 * only augments error values which are Error instances (= have the
39879 * built-in Error.prototype in their prototype chain) and are also
39880 * extensible. User error handlers have no limitations in this respect.
39881 */
39882
39883/* include removed: duk_internal.h */
39884
39885/*
39886 * Helper for calling a user error handler.
39887 *
39888 * 'thr' must be the currently active thread; the error handler is called
39889 * in its context. The valstack of 'thr' must have the error value on
39890 * top, and will be replaced by another error value based on the return
39891 * value of the error handler.
39892 *
39893 * The helper calls duk_handle_call() recursively in protected mode.
39894 * Before that call happens, no longjmps should happen; as a consequence,
39895 * we must assume that the valstack contains enough temporary space for
39896 * arguments and such.
39897 *
39898 * While the error handler runs, any errors thrown will not trigger a
39899 * recursive error handler call (this is implemented using a heap level
39900 * flag which will "follow" through any coroutines resumed inside the
39901 * error handler). If the error handler is not callable or throws an
39902 * error, the resulting error replaces the original error (for Duktape
39903 * internal errors, duk_error_throw.c further substitutes this error with
39904 * a DoubleError which is not ideal). This would be easy to change and
39905 * even signal to the caller.
39906 *
39907 * The user error handler is stored in 'Duktape.errCreate' or
39908 * 'Duktape.errThrow' depending on whether we're augmenting the error at
39909 * creation or throw time. There are several alternatives to this approach,
39910 * see doc/error-objects.rst for discussion.
39911 *
39912 * Note: since further longjmp()s may occur while calling the error handler
39913 * (for many reasons, e.g. a labeled 'break' inside the handler), the
39914 * caller can make no assumptions on the thr->heap->lj state after the
39915 * call (this affects especially duk_error_throw.c). This is not an issue
39916 * as long as the caller writes to the lj state only after the error handler
39917 * finishes.
39918 */
39919
39920#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
39921DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
39922 duk_context *ctx = (duk_context *) thr;
39923 duk_tval *tv_hnd;
39924 duk_small_uint_t call_flags;
39925 duk_int_t rc;
39926
39927 DUK_ASSERT(thr != NULL);
39928 DUK_ASSERT(thr->heap != NULL);
39929 DUK_ASSERT_DISABLE(stridx_cb >= 0); /* unsigned */
39930 DUK_ASSERT(stridx_cb < DUK_HEAP_NUM_STRINGS);
39931
39932 if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
39933 DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore"));
39934 return;
39935 }
39936
39937 /*
39938 * Check whether or not we have an error handler.
39939 *
39940 * We must be careful of not triggering an error when looking up the
39941 * property. For instance, if the property is a getter, we don't want
39942 * to call it, only plain values are allowed. The value, if it exists,
39943 * is not checked. If the value is not a function, a TypeError happens
39944 * when it is called and that error replaces the original one.
39945 */
39946
39947 DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */
39948
39949 /* [ ... errval ] */
39950
39951 if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
39952 /* When creating built-ins, some of the built-ins may not be set
39953 * and we want to tolerate that when throwing errors.
39954 */
39955 DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
39956 return;
39957 }
39958 tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap,
39959 thr->builtins[DUK_BIDX_DUKTAPE],
39960 DUK_HTHREAD_GET_STRING(thr, stridx_cb));
39961 if (tv_hnd == NULL) {
39962 DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
39963 (duk_tval *) tv_hnd));
39964 return;
39965 }
39966 DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
39967 (duk_tval *) tv_hnd));
39968 duk_push_tval(ctx, tv_hnd);
39969
39970 /* [ ... errval errhandler ] */
39971
39972 duk_insert(ctx, -2); /* -> [ ... errhandler errval ] */
39973 duk_push_undefined(ctx);
39974 duk_insert(ctx, -2); /* -> [ ... errhandler undefined(= this) errval ] */
39975
39976 /* [ ... errhandler undefined errval ] */
39977
39978 /*
39979 * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
39980 * recursion depth limit (and won't increase it either). This is
39981 * dangerous, but useful because it allows the error handler to run
39982 * even if the original error is caused by C recursion depth limit.
39983 *
39984 * The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
39985 * duration of the error handler and cleared afterwards. This flag
39986 * prevents the error handler from running recursively. The flag is
39987 * heap level so that the flag properly controls even coroutines
39988 * launched by an error handler. Since the flag is heap level, it is
39989 * critical to restore it correctly.
39990 *
39991 * We ignore errors now: a success return and an error value both
39992 * replace the original error value. (This would be easy to change.)
39993 */
39994
39995 DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */
39996 DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
39997
39998 call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
39999
40000 rc = duk_handle_call_protected(thr,
40001 1, /* num args */
40002 call_flags); /* call_flags */
40003 DUK_UNREF(rc); /* no need to check now: both success and error are OK */
40004
40005 DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
40006 DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);
40007
40008 /* [ ... errval ] */
40009}
40010#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
40011
40012/*
40013 * Add ._Tracedata to an error on the stack top.
40014 */
40015
40016#if defined(DUK_USE_TRACEBACKS)
40017DUK_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) {
40018 duk_context *ctx = (duk_context *) thr;
40019 duk_small_uint_t depth;
40020 duk_int_t i, i_min;
40021 duk_uarridx_t arr_idx;
40022 duk_double_t d;
40023
40024 DUK_ASSERT(thr != NULL);
40025 DUK_ASSERT(thr_callstack != NULL);
40026 DUK_ASSERT(ctx != NULL);
40027
40028 /* [ ... error ] */
40029
40030 /*
40031 * The traceback format is pretty arcane in an attempt to keep it compact
40032 * and cheap to create. It may change arbitrarily from version to version.
40033 * It should be decoded/accessed through version specific accessors only.
40034 *
40035 * See doc/error-objects.rst.
40036 */
40037
40038 DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
40039 (duk_tval *) duk_get_tval(ctx, -1)));
40040
40041 duk_push_array(ctx); /* XXX: specify array size, as we know it */
40042 arr_idx = 0;
40043
40044 /* Compiler SyntaxErrors (and other errors) come first, and are
40045 * blamed by default (not flagged "noblame").
40046 */
40047 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
40048 duk_push_hstring(ctx, thr->compile_ctx->h_filename);
40049 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40050 arr_idx++;
40051
40052 duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line); /* (flags<<32) + (line), flags = 0 */
40053 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40054 arr_idx++;
40055 }
40056
40057 /* Filename/line from C macros (__FILE__, __LINE__) are added as an
40058 * entry with a special format: (string, number). The number contains
40059 * the line and flags.
40060 */
40061
40062 /* XXX: optimize: allocate an array part to the necessary size (upwards
40063 * estimate) and fill in the values directly into the array part; finally
40064 * update 'length'.
40065 */
40066
40067 /* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype
40068 * has write-protected array index named properties. This was seen as DoubleErrors
40069 * in e.g. some test262 test cases. Using duk_xdef_prop_index() is better but heavier.
40070 * The best fix is to fill in the tracedata directly into the array part. There are
40071 * no side effect concerns if the array part is allocated directly and only INCREFs
40072 * happen after that.
40073 */
40074
40075 /* [ ... error arr ] */
40076
40077 if (c_filename) {
40078 duk_push_string(ctx, c_filename);
40079 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40080 arr_idx++;
40081
40082 d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
40083 (duk_double_t) c_line;
40084 duk_push_number(ctx, d);
40085 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40086 arr_idx++;
40087 }
40088
40089 /* traceback depth doesn't take into account the filename/line
40090 * special handling above (intentional)
40091 */
40092 depth = DUK_USE_TRACEBACK_DEPTH;
40093 i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
40094 DUK_ASSERT(i_min >= 0);
40095
40096 /* [ ... error arr ] */
40097
40098 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
40099 for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
40100 duk_uint32_t pc;
40101
40102 /*
40103 * Note: each API operation potentially resizes the callstack,
40104 * so be careful to re-lookup after every operation. Currently
40105 * these is no issue because we don't store a temporary 'act'
40106 * pointer at all. (This would be a non-issue if we operated
40107 * directly on the array part.)
40108 */
40109
40110 /* [... arr] */
40111
40112 DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0); /* unsigned */
40113
40114 /* Add function object. */
40115 duk_push_tval(ctx, &(thr_callstack->callstack + i)->tv_func);
40116 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40117 arr_idx++;
40118
40119 /* Add a number containing: pc, activation flags.
40120 *
40121 * PC points to next instruction, find offending PC. Note that
40122 * PC == 0 for native code.
40123 */
40124 pc = duk_hthread_get_act_prev_pc(thr_callstack, thr_callstack->callstack + i);
40125 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
40126 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
40127 d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
40128 duk_push_number(ctx, d); /* -> [... arr num] */
40129 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40130 arr_idx++;
40131 }
40132
40133 /* XXX: set with duk_hobject_set_length() when tracedata is filled directly */
40134 duk_push_uint(ctx, (duk_uint_t) arr_idx);
40135 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
40136
40137 /* [ ... error arr ] */
40138
40139 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
40140}
40141#endif /* DUK_USE_TRACEBACKS */
40142
40143/*
40144 * Add .fileName and .lineNumber to an error on the stack top.
40145 */
40146
40147#if !defined(DUK_USE_TRACEBACKS)
40148DUK_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) {
40149 duk_context *ctx;
40150#if defined(DUK_USE_ASSERTIONS)
40151 duk_int_t entry_top;
40152#endif
40153
40154 ctx = (duk_context *) thr;
40155#if defined(DUK_USE_ASSERTIONS)
40156 entry_top = duk_get_top(ctx);
40157#endif
40158
40159 /*
40160 * If tracebacks are disabled, 'fileName' and 'lineNumber' are added
40161 * as plain own properties. Since Error.prototype has accessors of
40162 * the same name, we need to define own properties directly (cannot
40163 * just use e.g. duk_put_prop_stridx). Existing properties are not
40164 * overwritten in case they already exist.
40165 */
40166
40167 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
40168 /* Compiler SyntaxError (or other error) gets the primary blame.
40169 * Currently no flag to prevent blaming.
40170 */
40171 duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
40172 duk_push_hstring(ctx, thr->compile_ctx->h_filename);
40173 } else if (c_filename && !noblame_fileline) {
40174 /* C call site gets blamed next, unless flagged not to do so.
40175 * XXX: file/line is disabled in minimal builds, so disable this
40176 * too when appropriate.
40177 */
40178 duk_push_int(ctx, c_line);
40179 duk_push_string(ctx, c_filename);
40180 } else {
40181 /* Finally, blame the innermost callstack entry which has a
40182 * .fileName property.
40183 */
40184 duk_small_uint_t depth;
40185 duk_int_t i, i_min;
40186 duk_uint32_t ecma_line;
40187
40188 depth = DUK_USE_TRACEBACK_DEPTH;
40189 i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
40190 DUK_ASSERT(i_min >= 0);
40191
40192 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
40193 for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
40194 duk_activation *act;
40195 duk_hobject *func;
40196 duk_uint32_t pc;
40197
40198 DUK_UNREF(pc);
40199 act = thr_callstack->callstack + i;
40200 DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
40201
40202 func = DUK_ACT_GET_FUNC(act);
40203 if (func == NULL) {
40204 /* Lightfunc, not blamed now. */
40205 continue;
40206 }
40207
40208 /* PC points to next instruction, find offending PC,
40209 * PC == 0 for native code.
40210 */
40211 pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
40212 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
40213 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
40214 act = NULL; /* invalidated by pushes, so get out of the way */
40215
40216 duk_push_hobject(ctx, func);
40217
40218 /* [ ... error func ] */
40219
40220 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
40221 if (!duk_is_string(ctx, -1)) {
40222 duk_pop_2(ctx);
40223 continue;
40224 }
40225
40226 /* [ ... error func fileName ] */
40227
40228 ecma_line = 0;
40229#if defined(DUK_USE_PC2LINE)
40230 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
40231 ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc);
40232 } else {
40233 /* Native function, no relevant lineNumber. */
40234 }
40235#endif /* DUK_USE_PC2LINE */
40236 duk_push_u32(ctx, ecma_line);
40237
40238 /* [ ... error func fileName lineNumber ] */
40239
40240 duk_replace(ctx, -3);
40241
40242 /* [ ... error lineNumber fileName ] */
40243 goto define_props;
40244 }
40245
40246 /* No activation matches, use undefined for both .fileName and
40247 * .lineNumber (matches what we do with a _Tracedata based
40248 * no-match lookup.
40249 */
40250 duk_push_undefined(ctx);
40251 duk_push_undefined(ctx);
40252 }
40253
40254 define_props:
40255 /* [ ... error lineNumber fileName ] */
40256#if defined(DUK_USE_ASSERTIONS)
40257 DUK_ASSERT(duk_get_top(ctx) == entry_top + 2);
40258#endif
40259 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
40260 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
40261}
40262#endif /* !DUK_USE_TRACEBACKS */
40263
40264/*
40265 * Add line number to a compiler error.
40266 */
40267
40268DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
40269 duk_context *ctx;
40270
40271 /* Append a "(line NNN)" to the "message" property of any error
40272 * thrown during compilation. Usually compilation errors are
40273 * SyntaxErrors but they can also be out-of-memory errors and
40274 * the like.
40275 */
40276
40277 /* [ ... error ] */
40278
40279 ctx = (duk_context *) thr;
40280 DUK_ASSERT(duk_is_object(ctx, -1));
40281
40282 if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
40283 return;
40284 }
40285
40286 DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
40287 (duk_tval *) duk_get_tval(ctx, -1)));
40288
40289 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) {
40290 duk_push_sprintf(ctx, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
40291 duk_concat(ctx, 2);
40292 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
40293 } else {
40294 duk_pop(ctx);
40295 }
40296
40297 DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
40298 (duk_tval *) duk_get_tval(ctx, -1)));
40299}
40300
40301/*
40302 * Augment an error being created using Duktape specific properties
40303 * like _Tracedata or .fileName/.lineNumber.
40304 */
40305
40306#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
40307DUK_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) {
40308 duk_context *ctx = (duk_context *) thr;
40309#if defined(DUK_USE_ASSERTIONS)
40310 duk_int_t entry_top;
40311#endif
40312
40313#if defined(DUK_USE_ASSERTIONS)
40314 entry_top = duk_get_top(ctx);
40315#endif
40316 DUK_ASSERT(obj != NULL);
40317
40318 DUK_UNREF(obj); /* unreferenced w/o tracebacks */
40319 DUK_UNREF(ctx); /* unreferenced w/o asserts */
40320
40321 duk__add_compiler_error_line(thr);
40322
40323#if defined(DUK_USE_TRACEBACKS)
40324 /* If tracebacks are enabled, the '_Tracedata' property is the only
40325 * thing we need: 'fileName' and 'lineNumber' are virtual properties
40326 * which use '_Tracedata'.
40327 */
40328 if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
40329 DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
40330 } else {
40331 duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline);
40332 }
40333#else
40334 /* Without tracebacks the concrete .fileName and .lineNumber need
40335 * to be added directly.
40336 */
40337 duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline);
40338#endif
40339
40340#if defined(DUK_USE_ASSERTIONS)
40341 DUK_ASSERT(duk_get_top(ctx) == entry_top);
40342#endif
40343}
40344#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
40345
40346/*
40347 * Augment an error at creation time with _Tracedata/fileName/lineNumber
40348 * and allow a user error handler (if defined) to process/replace the error.
40349 * The error to be augmented is at the stack top.
40350 *
40351 * thr: thread containing the error value
40352 * thr_callstack: thread which should be used for generating callstack etc.
40353 * c_filename: C __FILE__ related to the error
40354 * c_line: C __LINE__ related to the error
40355 * noblame_fileline: if true, don't fileName/line as error source, otherwise use traceback
40356 * (needed because user code filename/line are reported but internal ones
40357 * are not)
40358 *
40359 * XXX: rename noblame_fileline to flags field; combine it to some existing
40360 * field (there are only a few call sites so this may not be worth it).
40361 */
40362
40363#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
40364DUK_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) {
40365 duk_context *ctx = (duk_context *) thr;
40366 duk_hobject *obj;
40367
40368 DUK_ASSERT(thr != NULL);
40369 DUK_ASSERT(thr_callstack != NULL);
40370 DUK_ASSERT(ctx != NULL);
40371
40372 /* [ ... error ] */
40373
40374 /*
40375 * Criteria for augmenting:
40376 *
40377 * - augmentation enabled in build (naturally)
40378 * - error value internal prototype chain contains the built-in
40379 * Error prototype object (i.e. 'val instanceof Error')
40380 *
40381 * Additional criteria for built-in augmenting:
40382 *
40383 * - error value is an extensible object
40384 */
40385
40386 obj = duk_get_hobject(ctx, -1);
40387 if (!obj) {
40388 DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
40389 return;
40390 }
40391 if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
40392 /* If the value has a prototype loop, it's critical not to
40393 * throw here. Instead, assume the value is not to be
40394 * augmented.
40395 */
40396 DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment"));
40397 return;
40398 }
40399 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
40400 DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
40401 duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
40402 } else {
40403 DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
40404 }
40405
40406 /* [ ... error ] */
40407
40408#if defined(DUK_USE_ERRCREATE)
40409 duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE);
40410#endif
40411}
40412#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
40413
40414/*
40415 * Augment an error at throw time; allow a user error handler (if defined)
40416 * to process/replace the error. The error to be augmented is at the
40417 * stack top.
40418 */
40419
40420#if defined(DUK_USE_AUGMENT_ERROR_THROW)
40421DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
40422#if defined(DUK_USE_ERRTHROW)
40423 duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW);
40424#endif /* DUK_USE_ERRTHROW */
40425}
40426#endif /* DUK_USE_AUGMENT_ERROR_THROW */
40427#line 1 "duk_error_longjmp.c"
40428/*
40429 * Do a longjmp call, calling the fatal error handler if no
40430 * catchpoint exists.
40431 */
40432
40433/* include removed: duk_internal.h */
40434
40435DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
40436 DUK_ASSERT(thr != NULL);
40437
40438 DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
40439 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
40440 &thr->heap->lj.value1, &thr->heap->lj.value2));
40441
40442#if !defined(DUK_USE_CPP_EXCEPTIONS)
40443 /* If we don't have a jmpbuf_ptr, there is little we can do
40444 * except panic. The caller's expectation is that we never
40445 * return.
40446 *
40447 * With C++ exceptions we now just propagate an uncaught error
40448 * instead of invoking the fatal error handler. Because there's
40449 * a dummy jmpbuf for C++ exceptions now, this could be changed.
40450 */
40451 if (!thr->heap->lj.jmpbuf_ptr) {
40452
40453 DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
40454 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
40455 &thr->heap->lj.value1, &thr->heap->lj.value2));
40456
40457 duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
40458 DUK_UNREACHABLE();
40459 }
40460#endif /* DUK_USE_CPP_EXCEPTIONS */
40461
40462#if defined(DUK_USE_CPP_EXCEPTIONS)
40463 {
40464 duk_internal_exception exc; /* dummy */
40465 throw exc;
40466 }
40467#else /* DUK_USE_CPP_EXCEPTIONS */
40468 DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
40469#endif /* DUK_USE_CPP_EXCEPTIONS */
40470
40471 DUK_UNREACHABLE();
40472}
40473#line 1 "duk_error_misc.c"
40474/*
40475 * Error helpers
40476 */
40477
40478/* include removed: duk_internal.h */
40479
40480/*
40481 * Helper to walk the thread chain and see if there is an active error
40482 * catcher. Protected calls or finally blocks aren't considered catching.
40483 */
40484
40485#if defined(DUK_USE_DEBUGGER_SUPPORT) && \
40486 (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
40487DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
40488 /*
40489 * XXX: As noted above, a protected API call won't be counted as a
40490 * catcher. This is usually convenient, e.g. in the case of a top-
40491 * level duk_pcall(), but may not always be desirable. Perhaps add an
40492 * argument to treat them as catchers?
40493 */
40494
40495 duk_size_t i;
40496
40497 DUK_ASSERT(thr != NULL);
40498
40499 while (thr != NULL) {
40500 for (i = 0; i < thr->catchstack_top; i++) {
40501 duk_catcher *cat = thr->catchstack + i;
40502 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
40503 return 1; /* all we need to know */
40504 }
40505 }
40506 thr = thr->resumer;
40507 }
40508 return 0;
40509}
40510#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
40511
40512/*
40513 * Get prototype object for an integer error code.
40514 */
40515
40516DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) {
40517 switch (code) {
40518 case DUK_ERR_EVAL_ERROR:
40519 return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
40520 case DUK_ERR_RANGE_ERROR:
40521 return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
40522 case DUK_ERR_REFERENCE_ERROR:
40523 return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
40524 case DUK_ERR_SYNTAX_ERROR:
40525 return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
40526 case DUK_ERR_TYPE_ERROR:
40527 return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
40528 case DUK_ERR_URI_ERROR:
40529 return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
40530
40531 /* XXX: more specific error classes? */
40532 case DUK_ERR_UNIMPLEMENTED_ERROR:
40533 case DUK_ERR_INTERNAL_ERROR:
40534 case DUK_ERR_ALLOC_ERROR:
40535 case DUK_ERR_ASSERTION_ERROR:
40536 case DUK_ERR_API_ERROR:
40537 case DUK_ERR_ERROR:
40538 default:
40539 return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
40540 }
40541}
40542
40543/*
40544 * Exposed helper for setting up heap longjmp state.
40545 */
40546
40547DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) {
40548#if defined(DUK_USE_DEBUGGER_SUPPORT)
40549 /* If something is thrown with the debugger attached and nobody will
40550 * catch it, execution is paused before the longjmp, turning over
40551 * control to the debug client. This allows local state to be examined
40552 * before the stack is unwound. Errors are not intercepted when debug
40553 * message loop is active (e.g. for Eval).
40554 */
40555
40556 /* XXX: Allow customizing the pause and notify behavior at runtime
40557 * using debugger runtime flags. For now the behavior is fixed using
40558 * config options.
40559 */
40560#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
40561 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) &&
40562 !thr->heap->dbg_processing &&
40563 lj_type == DUK_LJ_TYPE_THROW) {
40564 duk_context *ctx = (duk_context *) thr;
40565 duk_bool_t fatal;
40566 duk_hobject *h_obj;
40567
40568 /* Don't intercept a DoubleError, we may have caused the initial double
40569 * fault and attempting to intercept it will cause us to be called
40570 * recursively and exhaust the C stack.
40571 */
40572 h_obj = duk_get_hobject(ctx, -1);
40573 if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
40574 DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting"));
40575 goto skip_throw_intercept;
40576 }
40577
40578 DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
40579
40580 fatal = !duk__have_active_catcher(thr);
40581
40582#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
40583 /* Report it to the debug client */
40584 duk_debug_send_throw(thr, fatal);
40585#endif
40586
40587#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
40588 if (fatal) {
40589 DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp"));
40590 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
40591 }
40592#endif
40593 }
40594
40595 skip_throw_intercept:
40596#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
40597#endif /* DUK_USE_DEBUGGER_SUPPORT */
40598
40599 thr->heap->lj.type = lj_type;
40600
40601 DUK_ASSERT(thr->valstack_top > thr->valstack);
40602 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */
40603
40604 duk_pop((duk_context *) thr);
40605}
40606#line 1 "duk_error_throw.c"
40607/*
40608 * Create and throw an Ecmascript error object based on a code and a message.
40609 *
40610 * Used when we throw errors internally. Ecmascript generated error objects
40611 * are created by Ecmascript code, and the throwing is handled by the bytecode
40612 * executor.
40613 */
40614
40615/* include removed: duk_internal.h */
40616
40617/*
40618 * Create and throw an error (originating from Duktape internally)
40619 *
40620 * Push an error object on top of the stack, possibly throw augmenting
40621 * the error, and finally longjmp.
40622 *
40623 * If an error occurs while we're dealing with the current error, we might
40624 * enter an infinite recursion loop. This is prevented by detecting a
40625 * "double fault" through the heap->handling_error flag; the recursion
40626 * then stops at the second level.
40627 */
40628
40629#ifdef DUK_USE_VERBOSE_ERRORS
40630DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) {
40631#else
40632DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
40633#endif
40634 duk_context *ctx = (duk_context *) thr;
40635 duk_bool_t double_error = thr->heap->handling_error;
40636
40637#ifdef DUK_USE_VERBOSE_ERRORS
40638 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
40639 (long) code, (const char *) msg,
40640 (const char *) filename, (long) line));
40641#else
40642 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code));
40643#endif
40644
40645 DUK_ASSERT(thr != NULL);
40646 DUK_ASSERT(ctx != NULL);
40647
40648 thr->heap->handling_error = 1;
40649
40650 if (!double_error) {
40651 /* Allow headroom for calls during error handling (see GH-191).
40652 * We allow space for 10 additional recursions, with one extra
40653 * for, e.g. a print() call at the deepest level.
40654 */
40655 DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX);
40656 thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11;
40657 }
40658
40659 DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */
40660
40661 /* Sync so that augmentation sees up-to-date activations, NULL
40662 * thr->ptr_curr_pc so that it's not used if side effects occur
40663 * in augmentation or longjmp handling.
40664 */
40665 duk_hthread_sync_and_null_currpc(thr);
40666
40667 /*
40668 * Create and push an error object onto the top of stack.
40669 * If a "double error" occurs, use a fixed error instance
40670 * to avoid further trouble.
40671 */
40672
40673 /* XXX: if attempt to push beyond allocated valstack, this double fault
40674 * handling fails miserably. We should really write the double error
40675 * directly to thr->heap->lj.value1 and avoid valstack use entirely.
40676 */
40677
40678 if (double_error) {
40679 if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
40680 DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance"));
40681 duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR);
40682 } else {
40683 DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
40684 "-> push the error code as a number"));
40685 duk_push_int(ctx, (duk_int_t) code);
40686 }
40687 } else {
40688 /* Error object is augmented at its creation here. */
40689 duk_require_stack(ctx, 1);
40690 /* XXX: unnecessary '%s' formatting here, but cannot use
40691 * 'msg' as a format string directly.
40692 */
40693#ifdef DUK_USE_VERBOSE_ERRORS
40694 duk_push_error_object_raw(ctx,
40695 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
40696 filename,
40697 line,
40698 "%s",
40699 (const char *) msg);
40700#else
40701 duk_push_error_object_raw(ctx,
40702 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
40703 NULL,
40704 0,
40705 NULL);
40706#endif
40707 }
40708
40709 /*
40710 * Augment error (throw time), unless alloc/double error
40711 */
40712
40713 if (double_error || code == DUK_ERR_ALLOC_ERROR) {
40714 DUK_D(DUK_DPRINT("alloc or double error: skip throw augmenting to avoid further trouble"));
40715 } else {
40716#if defined(DUK_USE_AUGMENT_ERROR_THROW)
40717 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
40718 (duk_tval *) duk_get_tval(ctx, -1)));
40719 duk_err_augment_error_throw(thr);
40720#endif
40721 }
40722
40723 /*
40724 * Finally, longjmp
40725 */
40726
40727 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
40728
40729 thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */
40730 thr->heap->handling_error = 0;
40731
40732 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
40733 (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
40734
40735 duk_err_longjmp(thr);
40736 DUK_UNREACHABLE();
40737}
40738
40739/*
40740 * Helper for C function call negative return values.
40741 */
40742
40743DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
40744 duk_context *ctx = (duk_context *) thr;
40745 const char *msg;
40746 duk_errcode_t code;
40747
40748 DUK_ASSERT(thr != NULL);
40749 DUK_ASSERT(rc < 0);
40750
40751 /* XXX: this generates quite large code - perhaps select the error
40752 * class based on the code and then just use the error 'name'?
40753 */
40754 /* XXX: shared strings */
40755
40756 code = -rc;
40757
40758 switch (rc) {
40759 case DUK_RET_UNIMPLEMENTED_ERROR: msg = "unimplemented"; break;
40760 case DUK_RET_UNSUPPORTED_ERROR: msg = "unsupported"; break;
40761 case DUK_RET_INTERNAL_ERROR: msg = "internal"; break;
40762 case DUK_RET_ALLOC_ERROR: msg = "alloc"; break;
40763 case DUK_RET_ASSERTION_ERROR: msg = "assertion"; break;
40764 case DUK_RET_API_ERROR: msg = "api"; break;
40765 case DUK_RET_UNCAUGHT_ERROR: msg = "uncaught"; break;
40766 case DUK_RET_ERROR: msg = "error"; break;
40767 case DUK_RET_EVAL_ERROR: msg = "eval"; break;
40768 case DUK_RET_RANGE_ERROR: msg = "range"; break;
40769 case DUK_RET_REFERENCE_ERROR: msg = "reference"; break;
40770 case DUK_RET_SYNTAX_ERROR: msg = "syntax"; break;
40771 case DUK_RET_TYPE_ERROR: msg = "type"; break;
40772 case DUK_RET_URI_ERROR: msg = "uri"; break;
40773 default: msg = "unknown"; break;
40774 }
40775
40776 DUK_ASSERT(msg != NULL);
40777
40778 /*
40779 * The __FILE__ and __LINE__ information is intentionally not used in the
40780 * creation of the error object, as it isn't useful in the tracedata. The
40781 * tracedata still contains the function which returned the negative return
40782 * code, and having the file/line of this function isn't very useful.
40783 */
40784
40785 duk_error_raw(ctx, code, NULL, 0, "%s error (rc %ld)", (const char *) msg, (long) rc);
40786 DUK_UNREACHABLE();
40787}
40788#line 1 "duk_hbuffer_alloc.c"
40789/*
40790 * duk_hbuffer allocation and freeing.
40791 */
40792
40793/* include removed: duk_internal.h */
40794
40795/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
40796 * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
40797 * allocation successful).
40798 */
40799DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
40800 duk_hbuffer *res = NULL;
40801 duk_size_t header_size;
40802 duk_size_t alloc_size;
40803
40804 DUK_ASSERT(heap != NULL);
40805 DUK_ASSERT(out_bufdata != NULL);
40806
40807 DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
40808
40809 /* Size sanity check. Should not be necessary because caller is
40810 * required to check this, but we don't want to cause a segfault
40811 * if the size wraps either in duk_size_t computation or when
40812 * storing the size in a 16-bit field.
40813 */
40814 if (size > DUK_HBUFFER_MAX_BYTELEN) {
40815 DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
40816 return NULL; /* no need to write 'out_bufdata' */
40817 }
40818
40819 if (flags & DUK_BUF_FLAG_EXTERNAL) {
40820 header_size = sizeof(duk_hbuffer_external);
40821 alloc_size = sizeof(duk_hbuffer_external);
40822 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
40823 header_size = sizeof(duk_hbuffer_dynamic);
40824 alloc_size = sizeof(duk_hbuffer_dynamic);
40825 } else {
40826 header_size = sizeof(duk_hbuffer_fixed);
40827 alloc_size = sizeof(duk_hbuffer_fixed) + size;
40828 DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */
40829 }
40830
40831 res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
40832 if (!res) {
40833 goto error;
40834 }
40835
40836 /* zero everything unless requested not to do so */
40837#if defined(DUK_USE_ZERO_BUFFER_DATA)
40838 DUK_MEMZERO((void *) res,
40839 (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
40840#else
40841 DUK_MEMZERO((void *) res, header_size);
40842#endif
40843
40844 if (flags & DUK_BUF_FLAG_EXTERNAL) {
40845 duk_hbuffer_external *h;
40846 h = (duk_hbuffer_external *) res;
40847 DUK_UNREF(h);
40848 *out_bufdata = NULL;
40849#if defined(DUK_USE_EXPLICIT_NULL_INIT)
40850#if defined(DUK_USE_HEAPPTR16)
40851/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
40852#else
40853 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
40854#endif
40855#endif
40856 DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
40857 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
40858 duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
40859 void *ptr;
40860
40861 if (size > 0) {
40862 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
40863 DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
40864#ifdef DUK_USE_ZERO_BUFFER_DATA
40865 ptr = DUK_ALLOC_ZEROED(heap, size);
40866#else
40867 ptr = DUK_ALLOC(heap, size);
40868#endif
40869 if (!ptr) {
40870 /* Because size > 0, NULL check is correct */
40871 goto error;
40872 }
40873 *out_bufdata = ptr;
40874
40875 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
40876 } else {
40877 *out_bufdata = NULL;
40878#if defined(DUK_USE_EXPLICIT_NULL_INIT)
40879#if defined(DUK_USE_HEAPPTR16)
40880/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
40881#else
40882 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
40883#endif
40884#endif
40885 DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
40886 }
40887 } else {
40888 *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1);
40889 }
40890
40891 DUK_HBUFFER_SET_SIZE(res, size);
40892
40893 DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
40894 if (flags & DUK_BUF_FLAG_DYNAMIC) {
40895 DUK_HBUFFER_SET_DYNAMIC(res);
40896 if (flags & DUK_BUF_FLAG_EXTERNAL) {
40897 DUK_HBUFFER_SET_EXTERNAL(res);
40898 }
40899 } else {
40900 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
40901 }
40902 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
40903
40904 DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
40905 return res;
40906
40907 error:
40908 DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
40909
40910 DUK_FREE(heap, res);
40911 return NULL; /* no need to write 'out_bufdata' */
40912}
40913
40914/* For indirect allocs. */
40915
40916DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
40917 duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
40918 DUK_UNREF(heap);
40919 return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
40920}
40921#line 1 "duk_hbuffer_ops.c"
40922/*
40923 * duk_hbuffer operations such as resizing and inserting/appending data to
40924 * a dynamic buffer.
40925 *
40926 * Append operations append to the end of the buffer and they are relatively
40927 * efficient: the buffer is grown with a "spare" part relative to the buffer
40928 * size to minimize reallocations. Insert operations need to move existing
40929 * data forward in the buffer with memmove() and are not very efficient.
40930 * They are used e.g. by the regexp compiler to "backpatch" regexp bytecode.
40931 */
40932
40933/* include removed: duk_internal.h */
40934
40935/*
40936 * Resizing
40937 */
40938
40939DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) {
40940 void *res;
40941 duk_size_t prev_size;
40942
40943 DUK_ASSERT(thr != NULL);
40944 DUK_ASSERT(buf != NULL);
40945 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
40946 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
40947
40948 /*
40949 * Maximum size check
40950 */
40951
40952 if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
40953 DUK_ERROR_RANGE(thr, "buffer too long");
40954 }
40955
40956 /*
40957 * Note: use indirect realloc variant just in case mark-and-sweep
40958 * (finalizers) might resize this same buffer during garbage
40959 * collection.
40960 */
40961
40962 res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
40963 if (res != NULL || new_size == 0) {
40964 /* 'res' may be NULL if new allocation size is 0. */
40965
40966 DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
40967 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf),
40968 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf),
40969 (void *) res,
40970 (long) new_size));
40971
40972 /*
40973 * The entire allocated buffer area, regardless of actual used
40974 * size, is kept zeroed in resizes for simplicity. If the buffer
40975 * is grown, zero the new part.
40976 */
40977
40978 prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
40979 if (new_size > prev_size) {
40980 DUK_ASSERT(new_size - prev_size > 0);
40981#ifdef DUK_USE_ZERO_BUFFER_DATA
40982 DUK_MEMZERO((void *) ((char *) res + prev_size),
40983 (duk_size_t) (new_size - prev_size));
40984#endif
40985 }
40986
40987 DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
40988 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
40989 } else {
40990 DUK_ERROR_ALLOC_DEFMSG(thr);
40991 }
40992
40993 DUK_ASSERT(res != NULL || new_size == 0);
40994}
40995
40996DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
40997 DUK_ASSERT(thr != NULL);
40998 DUK_ASSERT(buf != NULL);
40999 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
41000 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
41001
41002 duk_hbuffer_resize(thr, buf, 0);
41003}
41004/* include removed: duk_internal.h */
41005#line 2 "duk_hbufferobject_misc.c"
41006
41007#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
41008DUK_INTERNAL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len) {
41009 duk_uint_t buf_size;
41010 duk_uint_t buf_avail;
41011
41012 DUK_ASSERT(h_bufobj != NULL);
41013 DUK_ASSERT(h_bufobj->buf != NULL);
41014
41015 buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf);
41016 if (h_bufobj->offset > buf_size) {
41017 /* Slice starting point is beyond current length. */
41018 return 0;
41019 }
41020 buf_avail = buf_size - h_bufobj->offset;
41021
41022 return buf_avail >= len ? len : buf_avail;
41023}
41024#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
41025#line 1 "duk_heap_alloc.c"
41026/*
41027 * duk_heap allocation and freeing.
41028 */
41029
41030/* include removed: duk_internal.h */
41031
41032/* Constants for built-in string data depacking. */
41033#define DUK__BITPACK_LETTER_LIMIT 26
41034#define DUK__BITPACK_UNDERSCORE 26
41035#define DUK__BITPACK_FF 27
41036#define DUK__BITPACK_SWITCH1 29
41037#define DUK__BITPACK_SWITCH 30
41038#define DUK__BITPACK_SEVENBIT 31
41039
41040#if defined(DUK_USE_ROM_STRINGS)
41041/* Fixed seed value used with ROM strings. */
41042#define DUK__FIXED_HASH_SEED 0xabcd1234
41043#endif
41044
41045/*
41046 * Free a heap object.
41047 *
41048 * Free heap object and its internal (non-heap) pointers. Assumes that
41049 * caller has removed the object from heap allocated list or the string
41050 * intern table, and any weak references (which strings may have) have
41051 * been already dealt with.
41052 */
41053
41054DUK_INTERNAL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h) {
41055 DUK_ASSERT(heap != NULL);
41056 DUK_ASSERT(h != NULL);
41057
41058 DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
41059
41060 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
41061 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
41062 DUK_UNREF(f);
41063 /* Currently nothing to free; 'data' is a heap object */
41064 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
41065 duk_hnativefunction *f = (duk_hnativefunction *) h;
41066 DUK_UNREF(f);
41067 /* Currently nothing to free */
41068 } else if (DUK_HOBJECT_IS_THREAD(h)) {
41069 duk_hthread *t = (duk_hthread *) h;
41070 DUK_FREE(heap, t->valstack);
41071 DUK_FREE(heap, t->callstack);
41072 DUK_FREE(heap, t->catchstack);
41073 /* Don't free h->resumer because it exists in the heap.
41074 * Callstack entries also contain function pointers which
41075 * are not freed for the same reason.
41076 */
41077
41078 /* XXX: with 'caller' property the callstack would need
41079 * to be unwound to update the 'caller' properties of
41080 * functions in the callstack.
41081 */
41082 }
41083}
41084
41085DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) {
41086 DUK_ASSERT(heap != NULL);
41087 DUK_ASSERT(h != NULL);
41088
41089 if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) {
41090 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
41091 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
41092 DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
41093 }
41094}
41095
41096DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) {
41097 DUK_ASSERT(heap != NULL);
41098 DUK_ASSERT(h != NULL);
41099
41100 DUK_UNREF(heap);
41101 DUK_UNREF(h);
41102
41103#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
41104 if (DUK_HSTRING_HAS_EXTDATA(h)) {
41105 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
41106 h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
41107 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
41108 }
41109#endif
41110}
41111
41112DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
41113 DUK_ASSERT(heap);
41114 DUK_ASSERT(hdr);
41115
41116 DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
41117
41118 switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
41119 case DUK_HTYPE_STRING:
41120 duk_free_hstring_inner(heap, (duk_hstring *) hdr);
41121 break;
41122 case DUK_HTYPE_OBJECT:
41123 duk_free_hobject_inner(heap, (duk_hobject *) hdr);
41124 break;
41125 case DUK_HTYPE_BUFFER:
41126 duk_free_hbuffer_inner(heap, (duk_hbuffer *) hdr);
41127 break;
41128 default:
41129 DUK_UNREACHABLE();
41130 }
41131
41132 DUK_FREE(heap, hdr);
41133}
41134
41135/*
41136 * Free the heap.
41137 *
41138 * Frees heap-related non-heap-tracked allocations such as the
41139 * string intern table; then frees the heap allocated objects;
41140 * and finally frees the heap structure itself. Reference counts
41141 * and GC markers are ignored (and not updated) in this process,
41142 * and finalizers won't be called.
41143 *
41144 * The heap pointer and heap object pointers must not be used
41145 * after this call.
41146 */
41147
41148DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
41149 duk_heaphdr *curr;
41150 duk_heaphdr *next;
41151
41152 curr = heap->heap_allocated;
41153 while (curr) {
41154 /* We don't log or warn about freeing zero refcount objects
41155 * because they may happen with finalizer processing.
41156 */
41157
41158 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
41159 (duk_heaphdr *) curr));
41160 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
41161 duk_heap_free_heaphdr_raw(heap, curr);
41162 curr = next;
41163 }
41164}
41165
41166#if defined(DUK_USE_REFERENCE_COUNTING)
41167DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
41168 duk_heaphdr *curr;
41169 duk_heaphdr *next;
41170
41171 curr = heap->refzero_list;
41172 while (curr) {
41173 DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
41174 (duk_heaphdr *) curr));
41175 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
41176 duk_heap_free_heaphdr_raw(heap, curr);
41177 curr = next;
41178 }
41179}
41180#endif
41181
41182#if defined(DUK_USE_MARK_AND_SWEEP)
41183DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
41184 duk_heaphdr *curr;
41185 duk_heaphdr *next;
41186
41187 curr = heap->finalize_list;
41188 while (curr) {
41189 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
41190 (duk_heaphdr *) curr));
41191 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
41192 duk_heap_free_heaphdr_raw(heap, curr);
41193 curr = next;
41194 }
41195}
41196#endif
41197
41198DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
41199 /* strings are only tracked by stringtable */
41200 duk_heap_free_strtab(heap);
41201}
41202
41203DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
41204 duk_hthread *thr;
41205 duk_heaphdr *curr;
41206 duk_uint_t round_no;
41207 duk_size_t count_all;
41208 duk_size_t count_finalized;
41209 duk_size_t curr_limit;
41210
41211 DUK_ASSERT(heap != NULL);
41212 DUK_ASSERT(heap->heap_thread != NULL);
41213
41214#if defined(DUK_USE_REFERENCE_COUNTING)
41215 DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
41216#endif
41217#if defined(DUK_USE_MARK_AND_SWEEP)
41218 DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
41219#endif
41220
41221 /* XXX: here again finalizer thread is the heap_thread which needs
41222 * to be coordinated with finalizer thread fixes.
41223 */
41224 thr = heap->heap_thread;
41225 DUK_ASSERT(thr != NULL);
41226
41227 /* Prevent mark-and-sweep for the pending finalizers, also prevents
41228 * refzero handling from moving objects away from the heap_allocated
41229 * list. (The flag meaning is slightly abused here.)
41230 */
41231 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
41232 DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
41233
41234 curr_limit = 0; /* suppress warning, not used */
41235 for (round_no = 0; ; round_no++) {
41236 curr = heap->heap_allocated;
41237 count_all = 0;
41238 count_finalized = 0;
41239 while (curr) {
41240 count_all++;
41241 if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
41242 /* Only objects in heap_allocated may have finalizers. Check that
41243 * the object itself has a _Finalizer property (own or inherited)
41244 * so that we don't execute finalizers for e.g. Proxy objects.
41245 */
41246 DUK_ASSERT(thr != NULL);
41247 DUK_ASSERT(curr != NULL);
41248
41249 if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
41250 if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
41251 DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
41252 duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
41253 count_finalized++;
41254 }
41255 }
41256 }
41257 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
41258 }
41259
41260 /* Each round of finalizer execution may spawn new finalizable objects
41261 * which is normal behavior for some applications. Allow multiple
41262 * rounds of finalization, but use a shrinking limit based on the
41263 * first round to detect the case where a runaway finalizer creates
41264 * an unbounded amount of new finalizable objects. Finalizer rescue
41265 * is not supported: the semantics are unclear because most of the
41266 * objects being finalized here are already reachable. The finalizer
41267 * is given a boolean to indicate that rescue is not possible.
41268 *
41269 * See discussion in: https://github.com/svaarala/duktape/pull/473
41270 */
41271
41272 if (round_no == 0) {
41273 /* Cannot wrap: each object is at least 8 bytes so count is
41274 * at most 1/8 of that.
41275 */
41276 curr_limit = count_all * 2;
41277 } else {
41278 curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */
41279 }
41280 DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
41281 (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
41282
41283 if (count_finalized == 0) {
41284 DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
41285 break;
41286 }
41287 if (count_finalized >= curr_limit) {
41288 DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
41289 break;
41290 }
41291 }
41292
41293 DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
41294 DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
41295}
41296
41297DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
41298 DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
41299
41300#if defined(DUK_USE_DEBUG)
41301 duk_heap_dump_strtab(heap);
41302#endif
41303
41304#if defined(DUK_USE_DEBUGGER_SUPPORT)
41305 /* Detach a debugger if attached (can be called multiple times)
41306 * safely.
41307 */
41308 /* XXX: Add a flag to reject an attempt to re-attach? Otherwise
41309 * the detached callback may immediately reattach.
41310 */
41311 duk_debug_do_detach(heap);
41312#endif
41313
41314 /* Execute finalizers before freeing the heap, even for reachable
41315 * objects, and regardless of whether or not mark-and-sweep is
41316 * enabled. This gives finalizers the chance to free any native
41317 * resources like file handles, allocations made outside Duktape,
41318 * etc. This is quite tricky to get right, so that all finalizer
41319 * guarantees are honored.
41320 *
41321 * XXX: this perhaps requires an execution time limit.
41322 */
41323 DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
41324#if defined(DUK_USE_MARK_AND_SWEEP)
41325 /* Run mark-and-sweep a few times just in case (unreachable object
41326 * finalizers run already here). The last round must rescue objects
41327 * from the previous round without running any more finalizers. This
41328 * ensures rescued objects get their FINALIZED flag cleared so that
41329 * their finalizer is called once more in forced finalization to
41330 * satisfy finalizer guarantees. However, we don't want to run any
41331 * more finalizer because that'd required one more loop, and so on.
41332 */
41333 DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
41334 duk_heap_mark_and_sweep(heap, 0);
41335 DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
41336 duk_heap_mark_and_sweep(heap, 0);
41337 DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
41338 duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
41339#endif
41340
41341 DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
41342 duk__free_run_finalizers(heap);
41343
41344 /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
41345 * are on the heap allocated list.
41346 */
41347
41348 DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
41349 duk__free_allocated(heap);
41350
41351#if defined(DUK_USE_REFERENCE_COUNTING)
41352 DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
41353 duk__free_refzero_list(heap);
41354#endif
41355
41356#if defined(DUK_USE_MARK_AND_SWEEP)
41357 DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
41358 duk__free_markandsweep_finalize_list(heap);
41359#endif
41360
41361 DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
41362 duk__free_stringtable(heap);
41363
41364 DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
41365 heap->free_func(heap->heap_udata, heap);
41366}
41367
41368/*
41369 * Allocate a heap.
41370 *
41371 * String table is initialized with built-in strings from genbuiltins.py,
41372 * either by dynamically creating the strings or by referring to ROM strings.
41373 */
41374
41375#if defined(DUK_USE_ROM_STRINGS)
41376DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
41377#if defined(DUK_USE_ASSERTIONS)
41378 duk_small_uint_t i;
41379#endif
41380
41381 /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
41382 * so nothing to initialize for strs[].
41383 */
41384
41385#if defined(DUK_USE_ASSERTIONS)
41386 for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) {
41387 duk_uint32_t hash;
41388 const duk_hstring *h;
41389 h = duk_rom_strings[i];
41390 DUK_ASSERT(h != NULL);
41391 hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
41392 DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx",
41393 (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
41394 DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
41395 }
41396#endif
41397 return 1;
41398}
41399#else /* DUK_USE_ROM_STRINGS */
41400DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
41401 duk_bitdecoder_ctx bd_ctx;
41402 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
41403 duk_small_uint_t i, j;
41404
41405 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
41406 bd->data = (const duk_uint8_t *) duk_strings_data;
41407 bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
41408
41409 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
41410 duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
41411 duk_hstring *h;
41412 duk_small_uint_t len;
41413 duk_small_uint_t mode;
41414 duk_small_uint_t t;
41415
41416 len = duk_bd_decode(bd, 5);
41417 mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
41418 for (j = 0; j < len; j++) {
41419 t = duk_bd_decode(bd, 5);
41420 if (t < DUK__BITPACK_LETTER_LIMIT) {
41421 t = t + DUK_ASC_UC_A + mode;
41422 } else if (t == DUK__BITPACK_UNDERSCORE) {
41423 t = DUK_ASC_UNDERSCORE;
41424 } else if (t == DUK__BITPACK_FF) {
41425 /* Internal keys are prefixed with 0xFF in the stringtable
41426 * (which makes them invalid UTF-8 on purpose).
41427 */
41428 t = 0xff;
41429 } else if (t == DUK__BITPACK_SWITCH1) {
41430 t = duk_bd_decode(bd, 5);
41431 DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
41432 DUK_ASSERT(t <= 25);
41433 t = t + DUK_ASC_UC_A + (mode ^ 32);
41434 } else if (t == DUK__BITPACK_SWITCH) {
41435 mode = mode ^ 32;
41436 t = duk_bd_decode(bd, 5);
41437 DUK_ASSERT_DISABLE(t >= 0);
41438 DUK_ASSERT(t <= 25);
41439 t = t + DUK_ASC_UC_A + mode;
41440 } else if (t == DUK__BITPACK_SEVENBIT) {
41441 t = duk_bd_decode(bd, 7);
41442 }
41443 tmp[j] = (duk_uint8_t) t;
41444 }
41445
41446 /* No need to length check string: it will never exceed even
41447 * the 16-bit length maximum.
41448 */
41449 DUK_ASSERT(len <= 0xffffUL);
41450 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
41451 h = duk_heap_string_intern(heap, tmp, len);
41452 if (!h) {
41453 goto error;
41454 }
41455 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
41456
41457 /* Special flags checks. Since these strings are always
41458 * reachable and a string cannot appear twice in the string
41459 * table, there's no need to check/set these flags elsewhere.
41460 * The 'internal' flag is set by string intern code.
41461 */
41462 if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
41463 DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
41464 }
41465 if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
41466 DUK_HSTRING_SET_RESERVED_WORD(h);
41467 if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
41468 DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
41469 }
41470 }
41471
41472 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
41473
41474 /* XXX: The incref macro takes a thread pointer but doesn't
41475 * use it right now.
41476 */
41477 DUK_HSTRING_INCREF(_never_referenced_, h);
41478
41479#if defined(DUK_USE_HEAPPTR16)
41480 heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
41481#else
41482 heap->strs[i] = h;
41483#endif
41484 }
41485
41486 return 1;
41487
41488 error:
41489 return 0;
41490}
41491#endif /* DUK_USE_ROM_STRINGS */
41492
41493DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
41494 duk_hthread *thr;
41495
41496 DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
41497 thr = duk_hthread_alloc(heap,
41498 DUK_HOBJECT_FLAG_EXTENSIBLE |
41499 DUK_HOBJECT_FLAG_THREAD |
41500 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
41501 if (!thr) {
41502 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
41503 return 0;
41504 }
41505 thr->state = DUK_HTHREAD_STATE_INACTIVE;
41506#if defined(DUK_USE_ROM_STRINGS)
41507 /* No strs[] pointer. */
41508#else /* DUK_USE_ROM_STRINGS */
41509#if defined(DUK_USE_HEAPPTR16)
41510 thr->strs16 = heap->strs16;
41511#else
41512 thr->strs = heap->strs;
41513#endif
41514#endif /* DUK_USE_ROM_STRINGS */
41515
41516 heap->heap_thread = thr;
41517 DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */
41518
41519 /* 'thr' is now reachable */
41520
41521 if (!duk_hthread_init_stacks(heap, thr)) {
41522 return 0;
41523 }
41524
41525 /* XXX: this may now fail, and is not handled correctly */
41526 duk_hthread_create_builtin_objects(thr);
41527
41528 /* default prototype (Note: 'thr' must be reachable) */
41529 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
41530
41531 return 1;
41532}
41533
41534#if defined(DUK_USE_DEBUG)
41535#define DUK__DUMPSZ(t) do { \
41536 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
41537 } while (0)
41538
41539/* These is not 100% because format would need to be non-portable "long long".
41540 * Also print out as doubles to catch cases where the "long" type is not wide
41541 * enough; the limits will then not be printed accurately but the magnitude
41542 * will be correct.
41543 */
41544#define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
41545 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
41546 (long) (a), (long) (b), \
41547 (double) (a), (double) (b))); \
41548 } while (0)
41549#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
41550 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
41551 (unsigned long) (a), (unsigned long) (b), \
41552 (double) (a), (double) (b))); \
41553 } while (0)
41554#define DUK__DUMPLM_SIGNED(t) do { \
41555 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
41556 } while (0)
41557#define DUK__DUMPLM_UNSIGNED(t) do { \
41558 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
41559 } while (0)
41560
41561DUK_LOCAL void duk__dump_type_sizes(void) {
41562 DUK_D(DUK_DPRINT("sizeof()"));
41563
41564 /* basic platform types */
41565 DUK__DUMPSZ(char);
41566 DUK__DUMPSZ(short);
41567 DUK__DUMPSZ(int);
41568 DUK__DUMPSZ(long);
41569 DUK__DUMPSZ(double);
41570 DUK__DUMPSZ(void *);
41571 DUK__DUMPSZ(size_t);
41572
41573 /* basic types from duk_features.h */
41574 DUK__DUMPSZ(duk_uint8_t);
41575 DUK__DUMPSZ(duk_int8_t);
41576 DUK__DUMPSZ(duk_uint16_t);
41577 DUK__DUMPSZ(duk_int16_t);
41578 DUK__DUMPSZ(duk_uint32_t);
41579 DUK__DUMPSZ(duk_int32_t);
41580 DUK__DUMPSZ(duk_uint64_t);
41581 DUK__DUMPSZ(duk_int64_t);
41582 DUK__DUMPSZ(duk_uint_least8_t);
41583 DUK__DUMPSZ(duk_int_least8_t);
41584 DUK__DUMPSZ(duk_uint_least16_t);
41585 DUK__DUMPSZ(duk_int_least16_t);
41586 DUK__DUMPSZ(duk_uint_least32_t);
41587 DUK__DUMPSZ(duk_int_least32_t);
41588#if defined(DUK_USE_64BIT_OPS)
41589 DUK__DUMPSZ(duk_uint_least64_t);
41590 DUK__DUMPSZ(duk_int_least64_t);
41591#endif
41592 DUK__DUMPSZ(duk_uint_fast8_t);
41593 DUK__DUMPSZ(duk_int_fast8_t);
41594 DUK__DUMPSZ(duk_uint_fast16_t);
41595 DUK__DUMPSZ(duk_int_fast16_t);
41596 DUK__DUMPSZ(duk_uint_fast32_t);
41597 DUK__DUMPSZ(duk_int_fast32_t);
41598#if defined(DUK_USE_64BIT_OPS)
41599 DUK__DUMPSZ(duk_uint_fast64_t);
41600 DUK__DUMPSZ(duk_int_fast64_t);
41601#endif
41602 DUK__DUMPSZ(duk_uintptr_t);
41603 DUK__DUMPSZ(duk_intptr_t);
41604 DUK__DUMPSZ(duk_uintmax_t);
41605 DUK__DUMPSZ(duk_intmax_t);
41606 DUK__DUMPSZ(duk_double_t);
41607
41608 /* important chosen base types */
41609 DUK__DUMPSZ(duk_int_t);
41610 DUK__DUMPSZ(duk_uint_t);
41611 DUK__DUMPSZ(duk_int_fast_t);
41612 DUK__DUMPSZ(duk_uint_fast_t);
41613 DUK__DUMPSZ(duk_small_int_t);
41614 DUK__DUMPSZ(duk_small_uint_t);
41615 DUK__DUMPSZ(duk_small_int_fast_t);
41616 DUK__DUMPSZ(duk_small_uint_fast_t);
41617
41618 /* some derived types */
41619 DUK__DUMPSZ(duk_codepoint_t);
41620 DUK__DUMPSZ(duk_ucodepoint_t);
41621 DUK__DUMPSZ(duk_idx_t);
41622 DUK__DUMPSZ(duk_errcode_t);
41623 DUK__DUMPSZ(duk_uarridx_t);
41624
41625 /* tval */
41626 DUK__DUMPSZ(duk_double_union);
41627 DUK__DUMPSZ(duk_tval);
41628
41629 /* structs from duk_forwdecl.h */
41630 DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */
41631 DUK__DUMPSZ(duk_heaphdr);
41632 DUK__DUMPSZ(duk_heaphdr_string);
41633 DUK__DUMPSZ(duk_hstring);
41634 DUK__DUMPSZ(duk_hstring_external);
41635 DUK__DUMPSZ(duk_hobject);
41636 DUK__DUMPSZ(duk_hcompiledfunction);
41637 DUK__DUMPSZ(duk_hnativefunction);
41638 DUK__DUMPSZ(duk_hthread);
41639 DUK__DUMPSZ(duk_hbuffer);
41640 DUK__DUMPSZ(duk_hbuffer_fixed);
41641 DUK__DUMPSZ(duk_hbuffer_dynamic);
41642 DUK__DUMPSZ(duk_hbuffer_external);
41643 DUK__DUMPSZ(duk_propaccessor);
41644 DUK__DUMPSZ(duk_propvalue);
41645 DUK__DUMPSZ(duk_propdesc);
41646 DUK__DUMPSZ(duk_heap);
41647#if defined(DUK_USE_STRTAB_CHAIN)
41648 DUK__DUMPSZ(duk_strtab_entry);
41649#endif
41650 DUK__DUMPSZ(duk_activation);
41651 DUK__DUMPSZ(duk_catcher);
41652 DUK__DUMPSZ(duk_strcache);
41653 DUK__DUMPSZ(duk_ljstate);
41654 DUK__DUMPSZ(duk_fixedbuffer);
41655 DUK__DUMPSZ(duk_bitdecoder_ctx);
41656 DUK__DUMPSZ(duk_bitencoder_ctx);
41657 DUK__DUMPSZ(duk_token);
41658 DUK__DUMPSZ(duk_re_token);
41659 DUK__DUMPSZ(duk_lexer_point);
41660 DUK__DUMPSZ(duk_lexer_ctx);
41661 DUK__DUMPSZ(duk_compiler_instr);
41662 DUK__DUMPSZ(duk_compiler_func);
41663 DUK__DUMPSZ(duk_compiler_ctx);
41664 DUK__DUMPSZ(duk_re_matcher_ctx);
41665 DUK__DUMPSZ(duk_re_compiler_ctx);
41666}
41667DUK_LOCAL void duk__dump_type_limits(void) {
41668 DUK_D(DUK_DPRINT("limits"));
41669
41670 /* basic types */
41671 DUK__DUMPLM_SIGNED(INT8);
41672 DUK__DUMPLM_UNSIGNED(UINT8);
41673 DUK__DUMPLM_SIGNED(INT_FAST8);
41674 DUK__DUMPLM_UNSIGNED(UINT_FAST8);
41675 DUK__DUMPLM_SIGNED(INT_LEAST8);
41676 DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
41677 DUK__DUMPLM_SIGNED(INT16);
41678 DUK__DUMPLM_UNSIGNED(UINT16);
41679 DUK__DUMPLM_SIGNED(INT_FAST16);
41680 DUK__DUMPLM_UNSIGNED(UINT_FAST16);
41681 DUK__DUMPLM_SIGNED(INT_LEAST16);
41682 DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
41683 DUK__DUMPLM_SIGNED(INT32);
41684 DUK__DUMPLM_UNSIGNED(UINT32);
41685 DUK__DUMPLM_SIGNED(INT_FAST32);
41686 DUK__DUMPLM_UNSIGNED(UINT_FAST32);
41687 DUK__DUMPLM_SIGNED(INT_LEAST32);
41688 DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
41689#if defined(DUK_USE_64BIT_OPS)
41690 DUK__DUMPLM_SIGNED(INT64);
41691 DUK__DUMPLM_UNSIGNED(UINT64);
41692 DUK__DUMPLM_SIGNED(INT_FAST64);
41693 DUK__DUMPLM_UNSIGNED(UINT_FAST64);
41694 DUK__DUMPLM_SIGNED(INT_LEAST64);
41695 DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
41696#endif
41697 DUK__DUMPLM_SIGNED(INTPTR);
41698 DUK__DUMPLM_UNSIGNED(UINTPTR);
41699 DUK__DUMPLM_SIGNED(INTMAX);
41700 DUK__DUMPLM_UNSIGNED(UINTMAX);
41701
41702 /* derived types */
41703 DUK__DUMPLM_SIGNED(INT);
41704 DUK__DUMPLM_UNSIGNED(UINT);
41705 DUK__DUMPLM_SIGNED(INT_FAST);
41706 DUK__DUMPLM_UNSIGNED(UINT_FAST);
41707 DUK__DUMPLM_SIGNED(SMALL_INT);
41708 DUK__DUMPLM_UNSIGNED(SMALL_UINT);
41709 DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
41710 DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
41711}
41712#undef DUK__DUMPSZ
41713#undef DUK__DUMPLM_SIGNED_RAW
41714#undef DUK__DUMPLM_UNSIGNED_RAW
41715#undef DUK__DUMPLM_SIGNED
41716#undef DUK__DUMPLM_UNSIGNED
41717
41718DUK_LOCAL void duk__dump_misc_options(void) {
41719 DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
41720 DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
41721 DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
41722 DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
41723 DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
41724#if defined(DUK_USE_PACKED_TVAL)
41725 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
41726#else
41727 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
41728#endif
41729#if defined(DUK_USE_VARIADIC_MACROS)
41730 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
41731#else
41732 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
41733#endif
41734#if defined(DUK_USE_INTEGER_LE)
41735 DUK_D(DUK_DPRINT("integer endianness: little"));
41736#elif defined(DUK_USE_INTEGER_ME)
41737 DUK_D(DUK_DPRINT("integer endianness: mixed"));
41738#elif defined(DUK_USE_INTEGER_BE)
41739 DUK_D(DUK_DPRINT("integer endianness: big"));
41740#else
41741 DUK_D(DUK_DPRINT("integer endianness: ???"));
41742#endif
41743#if defined(DUK_USE_DOUBLE_LE)
41744 DUK_D(DUK_DPRINT("IEEE double endianness: little"));
41745#elif defined(DUK_USE_DOUBLE_ME)
41746 DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
41747#elif defined(DUK_USE_DOUBLE_BE)
41748 DUK_D(DUK_DPRINT("IEEE double endianness: big"));
41749#else
41750 DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
41751#endif
41752}
41753#endif /* DUK_USE_DEBUG */
41754
41755DUK_INTERNAL
41756duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
41757 duk_realloc_function realloc_func,
41758 duk_free_function free_func,
41759 void *heap_udata,
41760 duk_fatal_function fatal_func) {
41761 duk_heap *res = NULL;
41762
41763 /* Silence a few global unused warnings here. */
41764 DUK_UNREF(duk_str_unsupported);
41765
41766 DUK_D(DUK_DPRINT("allocate heap"));
41767
41768 /*
41769 * Debug dump type sizes
41770 */
41771
41772#if defined(DUK_USE_DEBUG)
41773 duk__dump_misc_options();
41774 duk__dump_type_sizes();
41775 duk__dump_type_limits();
41776#endif
41777
41778 /*
41779 * If selftests enabled, run them as early as possible
41780 */
41781#if defined(DUK_USE_SELF_TESTS)
41782 DUK_D(DUK_DPRINT("running self tests"));
41783 duk_selftest_run_tests();
41784 DUK_D(DUK_DPRINT("self tests passed"));
41785#endif
41786
41787 /*
41788 * Computed values (e.g. INFINITY)
41789 */
41790
41791#if defined(DUK_USE_COMPUTED_NAN)
41792 do {
41793 /* Workaround for some exotic platforms where NAN is missing
41794 * and the expression (0.0 / 0.0) does NOT result in a NaN.
41795 * Such platforms use the global 'duk_computed_nan' which must
41796 * be initialized at runtime. Use 'volatile' to ensure that
41797 * the compiler will actually do the computation and not try
41798 * to do constant folding which might result in the original
41799 * problem.
41800 */
41801 volatile double dbl1 = 0.0;
41802 volatile double dbl2 = 0.0;
41803 duk_computed_nan = dbl1 / dbl2;
41804 } while (0);
41805#endif
41806
41807#if defined(DUK_USE_COMPUTED_INFINITY)
41808 do {
41809 /* Similar workaround for INFINITY. */
41810 volatile double dbl1 = 1.0;
41811 volatile double dbl2 = 0.0;
41812 duk_computed_infinity = dbl1 / dbl2;
41813 } while (0);
41814#endif
41815
41816 /*
41817 * Allocate heap struct
41818 *
41819 * Use a raw call, all macros expect the heap to be initialized
41820 */
41821
41822 res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
41823 if (!res) {
41824 goto error;
41825 }
41826
41827 /*
41828 * Zero the struct, and start initializing roughly in order
41829 */
41830
41831 DUK_MEMZERO(res, sizeof(*res));
41832
41833 /* explicit NULL inits */
41834#if defined(DUK_USE_EXPLICIT_NULL_INIT)
41835 res->heap_udata = NULL;
41836 res->heap_allocated = NULL;
41837#if defined(DUK_USE_REFERENCE_COUNTING)
41838 res->refzero_list = NULL;
41839 res->refzero_list_tail = NULL;
41840#endif
41841#if defined(DUK_USE_MARK_AND_SWEEP)
41842 res->finalize_list = NULL;
41843#endif
41844 res->heap_thread = NULL;
41845 res->curr_thread = NULL;
41846 res->heap_object = NULL;
41847#if defined(DUK_USE_STRTAB_CHAIN)
41848 /* nothing to NULL */
41849#elif defined(DUK_USE_STRTAB_PROBE)
41850#if defined(DUK_USE_HEAPPTR16)
41851 res->strtable16 = (duk_uint16_t *) NULL;
41852#else
41853 res->strtable = (duk_hstring **) NULL;
41854#endif
41855#endif
41856#if defined(DUK_USE_ROM_STRINGS)
41857 /* no res->strs[] */
41858#else /* DUK_USE_ROM_STRINGS */
41859#if defined(DUK_USE_HEAPPTR16)
41860 /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
41861#else
41862 {
41863 duk_small_uint_t i;
41864 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
41865 res->strs[i] = NULL;
41866 }
41867 }
41868#endif
41869#endif /* DUK_USE_ROM_STRINGS */
41870#if defined(DUK_USE_DEBUGGER_SUPPORT)
41871 res->dbg_read_cb = NULL;
41872 res->dbg_write_cb = NULL;
41873 res->dbg_peek_cb = NULL;
41874 res->dbg_read_flush_cb = NULL;
41875 res->dbg_write_flush_cb = NULL;
41876 res->dbg_request_cb = NULL;
41877 res->dbg_udata = NULL;
41878 res->dbg_step_thread = NULL;
41879#endif
41880#endif /* DUK_USE_EXPLICIT_NULL_INIT */
41881
41882 res->alloc_func = alloc_func;
41883 res->realloc_func = realloc_func;
41884 res->free_func = free_func;
41885 res->heap_udata = heap_udata;
41886 res->fatal_func = fatal_func;
41887
41888#if defined(DUK_USE_HEAPPTR16)
41889 /* XXX: zero assumption */
41890 res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL);
41891 res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res));
41892#endif
41893
41894 /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
41895
41896 res->call_recursion_depth = 0;
41897 res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
41898
41899 /* XXX: use the pointer as a seed for now: mix in time at least */
41900
41901 /* The casts through duk_intr_pt is to avoid the following GCC warning:
41902 *
41903 * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
41904 *
41905 * This still generates a /Wp64 warning on VS2010 when compiling for x86.
41906 */
41907#if defined(DUK_USE_ROM_STRINGS)
41908 /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */
41909 DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
41910 res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
41911#else /* DUK_USE_ROM_STRINGS */
41912 res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
41913#if !defined(DUK_USE_STRHASH_DENSE)
41914 res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
41915#endif
41916#endif /* DUK_USE_ROM_STRINGS */
41917 res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
41918
41919#if defined(DUK_USE_EXPLICIT_NULL_INIT)
41920 res->lj.jmpbuf_ptr = NULL;
41921#endif
41922 DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
41923
41924 DUK_TVAL_SET_UNDEFINED(&res->lj.value1);
41925 DUK_TVAL_SET_UNDEFINED(&res->lj.value2);
41926
41927#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
41928#error initial heap stringtable size is defined incorrectly
41929#endif
41930
41931 /*
41932 * Init stringtable: fixed variant
41933 */
41934
41935#if defined(DUK_USE_STRTAB_CHAIN)
41936 DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE);
41937#if defined(DUK_USE_EXPLICIT_NULL_INIT)
41938 {
41939 duk_small_uint_t i;
41940 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
41941#if defined(DUK_USE_HEAPPTR16)
41942 res->strtable[i].u.str16 = res->heapptr_null16;
41943#else
41944 res->strtable[i].u.str = NULL;
41945#endif
41946 }
41947 }
41948#endif /* DUK_USE_EXPLICIT_NULL_INIT */
41949#endif /* DUK_USE_STRTAB_CHAIN */
41950
41951 /*
41952 * Init stringtable: probe variant
41953 */
41954
41955#if defined(DUK_USE_STRTAB_PROBE)
41956#if defined(DUK_USE_HEAPPTR16)
41957 res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
41958 if (!res->strtable16) {
41959 goto error;
41960 }
41961#else /* DUK_USE_HEAPPTR16 */
41962 res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
41963 if (!res->strtable) {
41964 goto error;
41965 }
41966#endif /* DUK_USE_HEAPPTR16 */
41967 res->st_size = DUK_STRTAB_INITIAL_SIZE;
41968#if defined(DUK_USE_EXPLICIT_NULL_INIT)
41969 {
41970 duk_small_uint_t i;
41971 DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE);
41972 for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) {
41973#if defined(DUK_USE_HEAPPTR16)
41974 res->strtable16[i] = res->heapptr_null16;
41975#else
41976 res->strtable[i] = NULL;
41977#endif
41978 }
41979 }
41980#else /* DUK_USE_EXPLICIT_NULL_INIT */
41981#if defined(DUK_USE_HEAPPTR16)
41982 DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
41983#else
41984 DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
41985#endif
41986#endif /* DUK_USE_EXPLICIT_NULL_INIT */
41987#endif /* DUK_USE_STRTAB_PROBE */
41988
41989 /*
41990 * Init stringcache
41991 */
41992
41993#if defined(DUK_USE_EXPLICIT_NULL_INIT)
41994 {
41995 duk_small_uint_t i;
41996 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
41997 res->strcache[i].h = NULL;
41998 }
41999 }
42000#endif
42001
42002 /* XXX: error handling is incomplete. It would be cleanest if
42003 * there was a setjmp catchpoint, so that all init code could
42004 * freely throw errors. If that were the case, the return code
42005 * passing here could be removed.
42006 */
42007
42008 /*
42009 * Init built-in strings
42010 */
42011
42012 DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
42013 if (!duk__init_heap_strings(res)) {
42014 goto error;
42015 }
42016
42017 /*
42018 * Init the heap thread
42019 */
42020
42021 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
42022 if (!duk__init_heap_thread(res)) {
42023 goto error;
42024 }
42025
42026 DUK_ASSERT(res->heap_thread != NULL);
42027 res->rnd_state ^= (duk_uint32_t) DUK_USE_DATE_GET_NOW((duk_context *) res->heap_thread);
42028
42029 /*
42030 * Init the heap object
42031 */
42032
42033 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
42034 DUK_ASSERT(res->heap_thread != NULL);
42035 res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
42036 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
42037 if (!res->heap_object) {
42038 goto error;
42039 }
42040 DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
42041
42042 /*
42043 * All done
42044 */
42045
42046 DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
42047 return res;
42048
42049 error:
42050 DUK_D(DUK_DPRINT("heap allocation failed"));
42051
42052 if (res) {
42053 /* assumes that allocated pointers and alloc funcs are valid
42054 * if res exists
42055 */
42056 DUK_ASSERT(res->alloc_func != NULL);
42057 DUK_ASSERT(res->realloc_func != NULL);
42058 DUK_ASSERT(res->free_func != NULL);
42059 duk_heap_free(res);
42060 }
42061 return NULL;
42062}
42063
42064#undef DUK__BITPACK_LETTER_LIMIT
42065#undef DUK__BITPACK_UNDERSCORE
42066#undef DUK__BITPACK_FF
42067#undef DUK__BITPACK_SWITCH1
42068#undef DUK__BITPACK_SWITCH
42069#undef DUK__BITPACK_SEVENBIT
42070#undef DUK__FIXED_HASH_SEED
42071#line 1 "duk_heap_hashstring.c"
42072/*
42073 * String hash computation (interning).
42074 *
42075 * String hashing is performance critical because a string hash is computed
42076 * for all new strings which are candidates to be added to the string table.
42077 * However, strings actually added to the string table go through a codepoint
42078 * length calculation which dominates performance because it goes through
42079 * every byte of the input string (but only for strings added).
42080 *
42081 * The string hash algorithm should be fast, but on the other hand provide
42082 * good enough hashes to ensure both string table and object property table
42083 * hash tables work reasonably well (i.e., there aren't too many collisions
42084 * with real world inputs). Unless the hash is cryptographic, it's always
42085 * possible to craft inputs with maximal hash collisions.
42086 *
42087 * NOTE: The hash algorithms must match src/dukutil.py:duk_heap_hashstring()
42088 * for ROM string support!
42089 */
42090
42091/* include removed: duk_internal.h */
42092
42093#if defined(DUK_USE_STRHASH_DENSE)
42094/* Constants for duk_hashstring(). */
42095#define DUK__STRHASH_SHORTSTRING 4096L
42096#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L)
42097#define DUK__STRHASH_BLOCKSIZE 256L
42098
42099DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
42100 duk_uint32_t hash;
42101
42102 /* Use Murmurhash2 directly for short strings, and use "block skipping"
42103 * for long strings: hash an initial part and then sample the rest of
42104 * the string with reasonably sized chunks. An initial offset for the
42105 * sampling is computed based on a hash of the initial part of the string;
42106 * this is done to (usually) avoid the case where all long strings have
42107 * certain offset ranges which are never sampled.
42108 *
42109 * Skip should depend on length and bound the total time to roughly
42110 * logarithmic. With current values:
42111 *
42112 * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
42113 * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
42114 *
42115 * XXX: It would be better to compute the skip offset more "smoothly"
42116 * instead of having a few boundary values.
42117 */
42118
42119 /* note: mixing len into seed improves hashing when skipping */
42120 duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len);
42121
42122 if (len <= DUK__STRHASH_SHORTSTRING) {
42123 hash = duk_util_hashbytes(str, len, str_seed);
42124 } else {
42125 duk_size_t off;
42126 duk_size_t skip;
42127
42128 if (len <= DUK__STRHASH_MEDIUMSTRING) {
42129 skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
42130 } else {
42131 skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
42132 }
42133
42134 hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
42135 off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
42136
42137 /* XXX: inefficient loop */
42138 while (off < len) {
42139 duk_size_t left = len - off;
42140 duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
42141 hash ^= duk_util_hashbytes(str + off, now, str_seed);
42142 off += skip;
42143 }
42144 }
42145
42146#if defined(DUK_USE_STRHASH16)
42147 /* Truncate to 16 bits here, so that a computed hash can be compared
42148 * against a hash stored in a 16-bit field.
42149 */
42150 hash &= 0x0000ffffUL;
42151#endif
42152 return hash;
42153}
42154
42155#undef DUK__STRHASH_SHORTSTRING
42156#undef DUK__STRHASH_MEDIUMSTRING
42157#undef DUK__STRHASH_BLOCKSIZE
42158#else /* DUK_USE_STRHASH_DENSE */
42159DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
42160 duk_uint32_t hash;
42161 duk_size_t step;
42162 duk_size_t off;
42163
42164 /* Slightly modified "Bernstein hash" from:
42165 *
42166 * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
42167 *
42168 * Modifications: string skipping and reverse direction similar to
42169 * Lua 5.1.5, and different hash initializer.
42170 *
42171 * The reverse direction ensures last byte it always included in the
42172 * hash which is a good default as changing parts of the string are
42173 * more often in the suffix than in the prefix.
42174 */
42175
42176 hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */
42177 step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
42178 for (off = len; off >= step; off -= step) {
42179 DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */
42180 hash = (hash * 33) + str[off - 1];
42181 }
42182
42183#if defined(DUK_USE_STRHASH16)
42184 /* Truncate to 16 bits here, so that a computed hash can be compared
42185 * against a hash stored in a 16-bit field.
42186 */
42187 hash &= 0x0000ffffUL;
42188#endif
42189 return hash;
42190}
42191#endif /* DUK_USE_STRHASH_DENSE */
42192#line 1 "duk_heap_markandsweep.c"
42193/*
42194 * Mark-and-sweep garbage collection.
42195 */
42196
42197/* include removed: duk_internal.h */
42198
42199#ifdef DUK_USE_MARK_AND_SWEEP
42200
42201DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
42202DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
42203
42204/*
42205 * Misc
42206 */
42207
42208/* Select a thread for mark-and-sweep use.
42209 *
42210 * XXX: This needs to change later.
42211 */
42212DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) {
42213 if (heap->curr_thread) {
42214 return heap->curr_thread;
42215 }
42216 return heap->heap_thread; /* may be NULL, too */
42217}
42218
42219/*
42220 * Marking functions for heap types: mark children recursively
42221 */
42222
42223DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
42224 DUK_UNREF(heap);
42225 DUK_UNREF(h);
42226
42227 DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h));
42228 DUK_ASSERT(h);
42229
42230 /* nothing to process */
42231}
42232
42233DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
42234 duk_uint_fast32_t i;
42235
42236 DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));
42237
42238 DUK_ASSERT(h);
42239
42240 /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
42241
42242 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
42243 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
42244 if (!key) {
42245 continue;
42246 }
42247 duk__mark_heaphdr(heap, (duk_heaphdr *) key);
42248 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
42249 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
42250 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
42251 } else {
42252 duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
42253 }
42254 }
42255
42256 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
42257 duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
42258 }
42259
42260 /* hash part is a 'weak reference' and does not contribute */
42261
42262 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
42263
42264 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
42265 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
42266 duk_tval *tv, *tv_end;
42267 duk_hobject **fn, **fn_end;
42268
42269 /* 'data' is reachable through every compiled function which
42270 * contains a reference.
42271 */
42272
42273 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f));
42274
42275 if (DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f) != NULL) {
42276 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f);
42277 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f);
42278 while (tv < tv_end) {
42279 duk__mark_tval(heap, tv);
42280 tv++;
42281 }
42282
42283 fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f);
42284 fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f);
42285 while (fn < fn_end) {
42286 duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
42287 fn++;
42288 }
42289 } else {
42290 /* May happen in some out-of-memory corner cases. */
42291 DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping marking"));
42292 }
42293 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
42294 duk_hnativefunction *f = (duk_hnativefunction *) h;
42295 DUK_UNREF(f);
42296 /* nothing to mark */
42297 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
42298 duk_hbufferobject *b = (duk_hbufferobject *) h;
42299 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
42300 } else if (DUK_HOBJECT_IS_THREAD(h)) {
42301 duk_hthread *t = (duk_hthread *) h;
42302 duk_tval *tv;
42303
42304 tv = t->valstack;
42305 while (tv < t->valstack_top) {
42306 duk__mark_tval(heap, tv);
42307 tv++;
42308 }
42309
42310 for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
42311 duk_activation *act = t->callstack + i;
42312 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
42313 duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
42314 duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
42315#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
42316 duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
42317#endif
42318 }
42319
42320#if 0 /* nothing now */
42321 for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
42322 duk_catcher *cat = t->catchstack + i;
42323 }
42324#endif
42325
42326 duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
42327
42328 /* XXX: duk_small_uint_t would be enough for this loop */
42329 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
42330 duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
42331 }
42332 }
42333}
42334
42335/* recursion tracking happens here only */
42336DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
42337 DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
42338 (void *) h,
42339 (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
42340 if (!h) {
42341 return;
42342 }
42343#if defined(DUK_USE_ROM_OBJECTS)
42344 if (DUK_HEAPHDR_HAS_READONLY(h)) {
42345 DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h));
42346 return;
42347 }
42348#endif
42349 if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
42350 DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
42351 return;
42352 }
42353 DUK_HEAPHDR_SET_REACHABLE(h);
42354
42355 if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
42356 /* log this with a normal debug level because this should be relatively rare */
42357 DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
42358 DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
42359 DUK_HEAPHDR_SET_TEMPROOT(h);
42360 return;
42361 }
42362
42363 heap->mark_and_sweep_recursion_depth++;
42364
42365 switch ((int) DUK_HEAPHDR_GET_TYPE(h)) {
42366 case DUK_HTYPE_STRING:
42367 duk__mark_hstring(heap, (duk_hstring *) h);
42368 break;
42369 case DUK_HTYPE_OBJECT:
42370 duk__mark_hobject(heap, (duk_hobject *) h);
42371 break;
42372 case DUK_HTYPE_BUFFER:
42373 /* nothing to mark */
42374 break;
42375 default:
42376 DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h)));
42377 DUK_UNREACHABLE();
42378 }
42379
42380 heap->mark_and_sweep_recursion_depth--;
42381}
42382
42383DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
42384 DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
42385 if (!tv) {
42386 return;
42387 }
42388 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
42389 duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv));
42390 }
42391}
42392
42393/*
42394 * Mark the heap.
42395 */
42396
42397DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) {
42398 duk_small_uint_t i;
42399
42400 DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap));
42401
42402 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread);
42403 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object);
42404
42405 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
42406 duk_hstring *h = DUK_HEAP_GET_STRING(heap, i);
42407 duk__mark_heaphdr(heap, (duk_heaphdr *) h);
42408 }
42409
42410 duk__mark_tval(heap, &heap->lj.value1);
42411 duk__mark_tval(heap, &heap->lj.value2);
42412
42413#if defined(DUK_USE_DEBUGGER_SUPPORT)
42414 for (i = 0; i < heap->dbg_breakpoint_count; i++) {
42415 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename);
42416 }
42417#endif
42418}
42419
42420/*
42421 * Mark refzero_list objects.
42422 *
42423 * Objects on the refzero_list have no inbound references. They might have
42424 * outbound references to objects that we might free, which would invalidate
42425 * any references held by the refzero objects. A refzero object might also
42426 * be rescued by refcount finalization. Refzero objects are treated as
42427 * reachability roots to ensure they (or anything they point to) are not
42428 * freed in mark-and-sweep.
42429 */
42430
42431#ifdef DUK_USE_REFERENCE_COUNTING
42432DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) {
42433 duk_heaphdr *hdr;
42434
42435 DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap));
42436
42437 hdr = heap->refzero_list;
42438 while (hdr) {
42439 duk__mark_heaphdr(heap, hdr);
42440 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42441 }
42442}
42443#endif
42444
42445/*
42446 * Mark unreachable, finalizable objects.
42447 *
42448 * Such objects will be moved aside and their finalizers run later. They have
42449 * to be treated as reachability roots for their properties etc to remain
42450 * allocated. This marking is only done for unreachable values which would
42451 * be swept later (refzero_list is thus excluded).
42452 *
42453 * Objects are first marked FINALIZABLE and only then marked as reachability
42454 * roots; otherwise circular references might be handled inconsistently.
42455 */
42456
42457DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
42458 duk_hthread *thr;
42459 duk_heaphdr *hdr;
42460 duk_size_t count_finalizable = 0;
42461
42462 DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
42463
42464 thr = duk__get_temp_hthread(heap);
42465 DUK_ASSERT(thr != NULL);
42466
42467 hdr = heap->heap_allocated;
42468 while (hdr) {
42469 /* A finalizer is looked up from the object and up its prototype chain
42470 * (which allows inherited finalizers). A prototype loop must not cause
42471 * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a
42472 * prototype loop silently and indicate that the property doesn't exist.
42473 */
42474
42475 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
42476 DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT &&
42477 !DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
42478 duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
42479
42480 /* heaphdr:
42481 * - is not reachable
42482 * - is an object
42483 * - is not a finalized object
42484 * - has a finalizer
42485 */
42486
42487 DUK_DD(DUK_DDPRINT("unreachable heap object will be "
42488 "finalized -> mark as finalizable "
42489 "and treat as a reachability root: %p",
42490 (void *) hdr));
42491 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
42492 DUK_HEAPHDR_SET_FINALIZABLE(hdr);
42493 count_finalizable ++;
42494 }
42495
42496 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42497 }
42498
42499 if (count_finalizable == 0) {
42500 return;
42501 }
42502
42503 DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable",
42504 (long) count_finalizable));
42505
42506 hdr = heap->heap_allocated;
42507 while (hdr) {
42508 if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
42509 duk__mark_heaphdr(heap, hdr);
42510 }
42511
42512 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42513 }
42514
42515 /* Caller will finish the marking process if we hit a recursion limit. */
42516}
42517
42518/*
42519 * Mark objects on finalize_list.
42520 *
42521 */
42522
42523DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
42524 duk_heaphdr *hdr;
42525#ifdef DUK_USE_DEBUG
42526 duk_size_t count_finalize_list = 0;
42527#endif
42528
42529 DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
42530
42531 hdr = heap->finalize_list;
42532 while (hdr) {
42533 duk__mark_heaphdr(heap, hdr);
42534 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42535#ifdef DUK_USE_DEBUG
42536 count_finalize_list++;
42537#endif
42538 }
42539
42540#ifdef DUK_USE_DEBUG
42541 if (count_finalize_list > 0) {
42542 DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
42543 (long) count_finalize_list));
42544 }
42545#endif
42546}
42547
42548/*
42549 * Fallback marking handler if recursion limit is reached.
42550 *
42551 * Iterates 'temproots' until recursion limit is no longer hit. Note
42552 * that temproots may reside either in heap allocated list or the
42553 * refzero work list. This is a slow scan, but guarantees that we
42554 * finish with a bounded C stack.
42555 *
42556 * Note that nodes may have been marked as temproots before this
42557 * scan begun, OR they may have been marked during the scan (as
42558 * we process nodes recursively also during the scan). This is
42559 * intended behavior.
42560 */
42561
42562#ifdef DUK_USE_DEBUG
42563DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) {
42564#else
42565DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
42566#endif
42567 if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
42568 DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
42569 return;
42570 }
42571
42572 DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
42573 DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
42574 DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */
42575 duk__mark_heaphdr(heap, hdr);
42576
42577#ifdef DUK_USE_DEBUG
42578 (*count)++;
42579#endif
42580}
42581
42582DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
42583 duk_heaphdr *hdr;
42584#ifdef DUK_USE_DEBUG
42585 duk_size_t count;
42586#endif
42587
42588 DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap));
42589
42590 while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
42591 DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
42592
42593#ifdef DUK_USE_DEBUG
42594 count = 0;
42595#endif
42596 DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
42597
42598 hdr = heap->heap_allocated;
42599 while (hdr) {
42600#ifdef DUK_USE_DEBUG
42601 duk__handle_temproot(heap, hdr, &count);
42602#else
42603 duk__handle_temproot(heap, hdr);
42604#endif
42605 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42606 }
42607
42608 /* must also check refzero_list */
42609#ifdef DUK_USE_REFERENCE_COUNTING
42610 hdr = heap->refzero_list;
42611 while (hdr) {
42612#ifdef DUK_USE_DEBUG
42613 duk__handle_temproot(heap, hdr, &count);
42614#else
42615 duk__handle_temproot(heap, hdr);
42616#endif
42617 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42618 }
42619#endif /* DUK_USE_REFERENCE_COUNTING */
42620
42621#ifdef DUK_USE_DEBUG
42622 DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
42623#endif
42624 }
42625}
42626
42627/*
42628 * Finalize refcounts for heap elements just about to be freed.
42629 * This must be done for all objects before freeing to avoid any
42630 * stale pointer dereferences.
42631 *
42632 * Note that this must deduce the set of objects to be freed
42633 * identically to duk__sweep_heap().
42634 */
42635
42636#ifdef DUK_USE_REFERENCE_COUNTING
42637DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
42638 duk_hthread *thr;
42639 duk_heaphdr *hdr;
42640
42641 thr = duk__get_temp_hthread(heap);
42642 DUK_ASSERT(thr != NULL);
42643
42644 DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p",
42645 (void *) heap, (void *) thr));
42646
42647 hdr = heap->heap_allocated;
42648 while (hdr) {
42649 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
42650 /*
42651 * Unreachable object about to be swept. Finalize target refcounts
42652 * (objects which the unreachable object points to) without doing
42653 * refzero processing. Recursive decrefs are also prevented when
42654 * refzero processing is disabled.
42655 *
42656 * Value cannot be a finalizable object, as they have been made
42657 * temporarily reachable for this round.
42658 */
42659
42660 DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
42661 duk_heaphdr_refcount_finalize(thr, hdr);
42662 }
42663
42664 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42665 }
42666}
42667#endif /* DUK_USE_REFERENCE_COUNTING */
42668
42669/*
42670 * Clear (reachable) flags of refzero work list.
42671 */
42672
42673#ifdef DUK_USE_REFERENCE_COUNTING
42674DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) {
42675 duk_heaphdr *hdr;
42676
42677 DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap));
42678
42679 hdr = heap->refzero_list;
42680 while (hdr) {
42681 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
42682 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
42683 /* DUK_HEAPHDR_HAS_FINALIZED may or may not be set. */
42684 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
42685 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42686 }
42687}
42688#endif /* DUK_USE_REFERENCE_COUNTING */
42689
42690/*
42691 * Clear (reachable) flags of finalize_list
42692 *
42693 * We could mostly do in the sweep phase when we move objects from the
42694 * heap into the finalize_list. However, if a finalizer run is skipped
42695 * during a mark-and-sweep, the objects on the finalize_list will be marked
42696 * reachable during the next mark-and-sweep. Since they're already on the
42697 * finalize_list, no-one will be clearing their REACHABLE flag so we do it
42698 * here. (This now overlaps with the sweep handling in a harmless way.)
42699 */
42700
42701DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
42702 duk_heaphdr *hdr;
42703
42704 DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap));
42705
42706 hdr = heap->finalize_list;
42707 while (hdr) {
42708 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
42709 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
42710 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
42711 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
42712 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42713 }
42714}
42715
42716/*
42717 * Sweep stringtable
42718 */
42719
42720#if defined(DUK_USE_STRTAB_CHAIN)
42721
42722/* XXX: skip count_free w/o debug? */
42723#if defined(DUK_USE_HEAPPTR16)
42724DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) {
42725 duk_uint16_t h16 = *slot;
42726 duk_hstring *h;
42727 duk_uint16_t null16 = heap->heapptr_null16;
42728
42729 if (h16 == null16) {
42730 /* nop */
42731 return;
42732 }
42733 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16);
42734 DUK_ASSERT(h != NULL);
42735
42736 if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
42737 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
42738 (*count_keep)++;
42739 } else {
42740#if defined(DUK_USE_REFERENCE_COUNTING)
42741 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
42742#endif
42743 /* deal with weak references first */
42744 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
42745 *slot = null16;
42746
42747 /* free inner references (these exist e.g. when external
42748 * strings are enabled)
42749 */
42750 duk_free_hstring_inner(heap, h);
42751 DUK_FREE(heap, h);
42752 (*count_free)++;
42753 }
42754}
42755#else /* DUK_USE_HEAPPTR16 */
42756DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) {
42757 duk_hstring *h = *slot;
42758
42759 if (h == NULL) {
42760 /* nop */
42761 return;
42762 }
42763
42764 if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
42765 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
42766 (*count_keep)++;
42767 } else {
42768#if defined(DUK_USE_REFERENCE_COUNTING)
42769 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
42770#endif
42771 /* deal with weak references first */
42772 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
42773 *slot = NULL;
42774
42775 /* free inner references (these exist e.g. when external
42776 * strings are enabled)
42777 */
42778 duk_free_hstring_inner(heap, h);
42779 DUK_FREE(heap, h);
42780 (*count_free)++;
42781 }
42782}
42783#endif /* DUK_USE_HEAPPTR16 */
42784
42785DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) {
42786 duk_strtab_entry *e;
42787 duk_uint_fast32_t i;
42788 duk_size_t count_free = 0;
42789 duk_size_t count_keep = 0;
42790 duk_size_t j, n;
42791#if defined(DUK_USE_HEAPPTR16)
42792 duk_uint16_t *lst;
42793#else
42794 duk_hstring **lst;
42795#endif
42796
42797 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
42798
42799 /* Non-zero refcounts should not happen for unreachable strings,
42800 * because we refcount finalize all unreachable objects which
42801 * should have decreased unreachable string refcounts to zero
42802 * (even for cycles).
42803 */
42804
42805 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
42806 e = heap->strtable + i;
42807 if (e->listlen == 0) {
42808#if defined(DUK_USE_HEAPPTR16)
42809 duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free);
42810#else
42811 duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free);
42812#endif
42813 } else {
42814#if defined(DUK_USE_HEAPPTR16)
42815 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
42816#else
42817 lst = e->u.strlist;
42818#endif
42819 for (j = 0, n = e->listlen; j < n; j++) {
42820#if defined(DUK_USE_HEAPPTR16)
42821 duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free);
42822#else
42823 duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free);
42824#endif
42825 }
42826 }
42827 }
42828
42829 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
42830 (long) count_free, (long) count_keep));
42831 *out_count_keep = count_keep;
42832}
42833#endif /* DUK_USE_STRTAB_CHAIN */
42834
42835#if defined(DUK_USE_STRTAB_PROBE)
42836DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) {
42837 duk_hstring *h;
42838 duk_uint_fast32_t i;
42839#ifdef DUK_USE_DEBUG
42840 duk_size_t count_free = 0;
42841#endif
42842 duk_size_t count_keep = 0;
42843
42844 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
42845
42846 for (i = 0; i < heap->st_size; i++) {
42847#if defined(DUK_USE_HEAPPTR16)
42848 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
42849#else
42850 h = heap->strtable[i];
42851#endif
42852 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
42853 continue;
42854 } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
42855 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
42856 count_keep++;
42857 continue;
42858 }
42859
42860#ifdef DUK_USE_DEBUG
42861 count_free++;
42862#endif
42863
42864#if defined(DUK_USE_REFERENCE_COUNTING)
42865 /* Non-zero refcounts should not happen for unreachable strings,
42866 * because we refcount finalize all unreachable objects which
42867 * should have decreased unreachable string refcounts to zero
42868 * (even for cycles).
42869 */
42870 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
42871#endif
42872
42873 DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h));
42874
42875 /* deal with weak references first */
42876 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
42877
42878 /* remove the string (mark DELETED), could also call
42879 * duk_heap_string_remove() but that would be slow and
42880 * pointless because we already know the slot.
42881 */
42882#if defined(DUK_USE_HEAPPTR16)
42883 heap->strtable16[i] = heap->heapptr_deleted16;
42884#else
42885 heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap);
42886#endif
42887
42888 /* free inner references (these exist e.g. when external
42889 * strings are enabled)
42890 */
42891 duk_free_hstring_inner(heap, (duk_hstring *) h);
42892
42893 /* finally free the struct itself */
42894 DUK_FREE(heap, h);
42895 }
42896
42897#ifdef DUK_USE_DEBUG
42898 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
42899 (long) count_free, (long) count_keep));
42900#endif
42901 *out_count_keep = count_keep;
42902}
42903#endif /* DUK_USE_STRTAB_PROBE */
42904
42905/*
42906 * Sweep heap
42907 */
42908
42909DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) {
42910 duk_heaphdr *prev; /* last element that was left in the heap */
42911 duk_heaphdr *curr;
42912 duk_heaphdr *next;
42913#ifdef DUK_USE_DEBUG
42914 duk_size_t count_free = 0;
42915 duk_size_t count_finalize = 0;
42916 duk_size_t count_rescue = 0;
42917#endif
42918 duk_size_t count_keep = 0;
42919
42920 DUK_UNREF(flags);
42921 DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
42922
42923 prev = NULL;
42924 curr = heap->heap_allocated;
42925 heap->heap_allocated = NULL;
42926 while (curr) {
42927 /* Strings and ROM objects are never placed on the heap allocated list. */
42928 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING);
42929 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));
42930
42931 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
42932
42933 if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
42934 /*
42935 * Reachable object, keep
42936 */
42937
42938 DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr));
42939
42940 if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) {
42941 /*
42942 * If object has been marked finalizable, move it to the
42943 * "to be finalized" work list. It will be collected on
42944 * the next mark-and-sweep if it is still unreachable
42945 * after running the finalizer.
42946 */
42947
42948 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
42949 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
42950 DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr));
42951
42952#ifdef DUK_USE_DOUBLE_LINKED_HEAP
42953 if (heap->finalize_list) {
42954 DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr);
42955 }
42956 DUK_HEAPHDR_SET_PREV(heap, curr, NULL);
42957#endif
42958 DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list);
42959 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
42960 heap->finalize_list = curr;
42961#ifdef DUK_USE_DEBUG
42962 count_finalize++;
42963#endif
42964 } else {
42965 /*
42966 * Object will be kept; queue object back to heap_allocated (to tail)
42967 */
42968
42969 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
42970 /*
42971 * Object's finalizer was executed on last round, and
42972 * object has been happily rescued.
42973 */
42974
42975 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
42976 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
42977 DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr));
42978#ifdef DUK_USE_DEBUG
42979 count_rescue++;
42980#endif
42981 } else {
42982 /*
42983 * Plain, boring reachable object.
42984 */
42985 DUK_DD(DUK_DDPRINT("keep object: %!iO", curr));
42986 count_keep++;
42987 }
42988
42989 if (!heap->heap_allocated) {
42990 heap->heap_allocated = curr;
42991 }
42992 if (prev) {
42993 DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
42994 }
42995#ifdef DUK_USE_DOUBLE_LINKED_HEAP
42996 DUK_HEAPHDR_SET_PREV(heap, curr, prev);
42997#endif
42998 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
42999 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
43000 prev = curr;
43001 }
43002
43003 DUK_HEAPHDR_CLEAR_REACHABLE(curr);
43004 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
43005 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
43006
43007 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
43008 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
43009 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
43010
43011 curr = next;
43012 } else {
43013 /*
43014 * Unreachable object, free
43015 */
43016
43017 DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr));
43018
43019#if defined(DUK_USE_REFERENCE_COUNTING)
43020 /* Non-zero refcounts should not happen because we refcount
43021 * finalize all unreachable objects which should cancel out
43022 * refcounts (even for cycles).
43023 */
43024 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0);
43025#endif
43026 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
43027
43028 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
43029 DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr));
43030 }
43031
43032 /* Note: object cannot be a finalizable unreachable object, as
43033 * they have been marked temporarily reachable for this round,
43034 * and are handled above.
43035 */
43036
43037#ifdef DUK_USE_DEBUG
43038 count_free++;
43039#endif
43040
43041 /* weak refs should be handled here, but no weak refs for
43042 * any non-string objects exist right now.
43043 */
43044
43045 /* free object and all auxiliary (non-heap) allocs */
43046 duk_heap_free_heaphdr_raw(heap, curr);
43047
43048 curr = next;
43049 }
43050 }
43051 if (prev) {
43052 DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
43053 }
43054 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
43055
43056#ifdef DUK_USE_DEBUG
43057 DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
43058 (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
43059#endif
43060 *out_count_keep = count_keep;
43061}
43062
43063/*
43064 * Run (object) finalizers in the "to be finalized" work list.
43065 */
43066
43067DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
43068 duk_heaphdr *curr;
43069 duk_heaphdr *next;
43070#ifdef DUK_USE_DEBUG
43071 duk_size_t count = 0;
43072#endif
43073 duk_hthread *thr;
43074
43075 DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));
43076
43077 thr = duk__get_temp_hthread(heap);
43078 DUK_ASSERT(thr != NULL);
43079
43080 curr = heap->finalize_list;
43081 while (curr) {
43082 DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));
43083
43084 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */
43085 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */
43086 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
43087 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
43088 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
43089 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */
43090
43091 /* Keep heap->finalize_list up-to-date during the list walk.
43092 * This has no functional impact, but does matter e.g. for
43093 * duk_push_heapptr() asserts when assertions are enabled.
43094 */
43095 heap->finalize_list = curr;
43096
43097 if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
43098 /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
43099 * Next mark-and-sweep will collect the object unless it has
43100 * become reachable (i.e. rescued). FINALIZED prevents the
43101 * finalizer from being executed again before that.
43102 */
43103 duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
43104 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
43105
43106 /* XXX: could clear FINALIZED already here; now cleared in
43107 * next mark-and-sweep.
43108 */
43109 } else {
43110 /* Used during heap destruction: don't actually run finalizers
43111 * because we're heading into forced finalization. Instead,
43112 * queue finalizable objects back to the heap_allocated list.
43113 */
43114 DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
43115 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
43116 }
43117
43118 /* queue back to heap_allocated */
43119 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
43120 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
43121
43122 curr = next;
43123#ifdef DUK_USE_DEBUG
43124 count++;
43125#endif
43126 }
43127
43128 /* finalize_list will always be processed completely */
43129 heap->finalize_list = NULL;
43130
43131#ifdef DUK_USE_DEBUG
43132 DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
43133#endif
43134}
43135
43136/*
43137 * Object compaction.
43138 *
43139 * Compaction is assumed to never throw an error.
43140 */
43141
43142DUK_LOCAL int duk__protected_compact_object(duk_context *ctx) {
43143 /* XXX: for threads, compact value stack, call stack, catch stack? */
43144
43145 duk_hobject *obj = duk_get_hobject(ctx, -1);
43146 DUK_ASSERT(obj != NULL);
43147 duk_hobject_compact_props((duk_hthread *) ctx, obj);
43148 return 0;
43149}
43150
43151#ifdef DUK_USE_DEBUG
43152DUK_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) {
43153#else
43154DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
43155#endif
43156 duk_heaphdr *curr;
43157#ifdef DUK_USE_DEBUG
43158 duk_size_t old_size, new_size;
43159#endif
43160 duk_hobject *obj;
43161
43162 DUK_UNREF(heap);
43163
43164 curr = start;
43165 while (curr) {
43166 DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr));
43167
43168 if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) {
43169 goto next;
43170 }
43171 obj = (duk_hobject *) curr;
43172
43173#ifdef DUK_USE_DEBUG
43174 old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
43175 DUK_HOBJECT_GET_ASIZE(obj),
43176 DUK_HOBJECT_GET_HSIZE(obj));
43177#endif
43178
43179 DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
43180 duk_push_hobject((duk_context *) thr, obj);
43181 /* XXX: disable error handlers for duration of compaction? */
43182 duk_safe_call((duk_context *) thr, duk__protected_compact_object, 1, 0);
43183
43184#ifdef DUK_USE_DEBUG
43185 new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
43186 DUK_HOBJECT_GET_ASIZE(obj),
43187 DUK_HOBJECT_GET_HSIZE(obj));
43188#endif
43189
43190#ifdef DUK_USE_DEBUG
43191 (*p_count_compact)++;
43192 (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
43193#endif
43194
43195 next:
43196 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
43197#ifdef DUK_USE_DEBUG
43198 (*p_count_check)++;
43199#endif
43200 }
43201}
43202
43203DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
43204 /* XXX: which lists should participate? to be finalized? */
43205#ifdef DUK_USE_DEBUG
43206 duk_size_t count_check = 0;
43207 duk_size_t count_compact = 0;
43208 duk_size_t count_bytes_saved = 0;
43209#endif
43210 duk_hthread *thr;
43211
43212 DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
43213
43214 thr = duk__get_temp_hthread(heap);
43215 DUK_ASSERT(thr != NULL);
43216
43217#ifdef DUK_USE_DEBUG
43218 duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
43219 duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
43220#ifdef DUK_USE_REFERENCE_COUNTING
43221 duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved);
43222#endif
43223#else
43224 duk__compact_object_list(heap, thr, heap->heap_allocated);
43225 duk__compact_object_list(heap, thr, heap->finalize_list);
43226#ifdef DUK_USE_REFERENCE_COUNTING
43227 duk__compact_object_list(heap, thr, heap->refzero_list);
43228#endif
43229#endif
43230
43231#ifdef DUK_USE_DEBUG
43232 DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
43233 (long) count_check, (long) count_compact, (long) count_bytes_saved));
43234#endif
43235}
43236
43237/*
43238 * Assertion helpers.
43239 */
43240
43241#ifdef DUK_USE_ASSERTIONS
43242DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
43243 duk_heaphdr *hdr;
43244
43245 hdr = heap->heap_allocated;
43246 while (hdr) {
43247 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
43248 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
43249 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
43250 /* may have FINALIZED */
43251 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
43252 }
43253
43254#ifdef DUK_USE_REFERENCE_COUNTING
43255 hdr = heap->refzero_list;
43256 while (hdr) {
43257 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
43258 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
43259 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
43260 /* DUK_HEAPHDR_HAS_FINALIZED may be set if we're doing a
43261 * refzero finalization and mark-and-sweep gets triggered
43262 * during the finalizer.
43263 */
43264 /* DUK_HEAPHDR_HAS_FINALIZED may or may not be set. */
43265 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
43266 }
43267#endif /* DUK_USE_REFERENCE_COUNTING */
43268}
43269
43270#ifdef DUK_USE_REFERENCE_COUNTING
43271DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
43272 duk_heaphdr *hdr = heap->heap_allocated;
43273 while (hdr) {
43274 if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 &&
43275 DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
43276 /* An object may be in heap_allocated list with a zero
43277 * refcount if it has just been finalized and is waiting
43278 * to be collected by the next cycle.
43279 */
43280 } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) {
43281 /* An object may be in heap_allocated list with a zero
43282 * refcount also if it is a temporary object created by
43283 * a finalizer; because finalization now runs inside
43284 * mark-and-sweep, such objects will not be queued to
43285 * refzero_list and will thus appear here with refcount
43286 * zero.
43287 */
43288#if 0 /* this case can no longer occur because refcount is unsigned */
43289 } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) {
43290 DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O",
43291 (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0),
43292 (void *) hdr, (duk_heaphdr *) hdr));
43293 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0);
43294#endif
43295 }
43296 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
43297 }
43298}
43299#endif /* DUK_USE_REFERENCE_COUNTING */
43300#endif /* DUK_USE_ASSERTIONS */
43301
43302/*
43303 * Finalizer torture. Do one fake finalizer call which causes side effects
43304 * similar to one or more finalizers on actual objects.
43305 */
43306
43307#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
43308DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) {
43309 DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed"));
43310
43311 /* Require a lot of stack to force a value stack grow/shrink.
43312 * Recursive mark-and-sweep is prevented by allocation macros
43313 * so this won't trigger another mark-and-sweep.
43314 */
43315 duk_require_stack(ctx, 100000);
43316
43317 /* XXX: do something to force a callstack grow/shrink, perhaps
43318 * just a manual forced resize or a forced relocating realloc?
43319 */
43320
43321 return 0;
43322}
43323
43324DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) {
43325 duk_context *ctx;
43326 duk_int_t rc;
43327
43328 DUK_ASSERT(thr != NULL);
43329 ctx = (duk_context *) thr;
43330
43331 /* Avoid fake finalization when callstack limit has been reached.
43332 * Otherwise a callstack limit error will be created, then refzero'ed.
43333 */
43334 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
43335 thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
43336 DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer"));
43337 return;
43338 }
43339
43340 /* Run fake finalizer. Avoid creating unnecessary garbage. */
43341 duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/);
43342 rc = duk_pcall(ctx, 0 /*nargs*/);
43343 DUK_UNREF(rc); /* ignored */
43344 duk_pop(ctx);
43345}
43346#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
43347
43348/*
43349 * Main mark-and-sweep function.
43350 *
43351 * 'flags' represents the features requested by the caller. The current
43352 * heap->mark_and_sweep_base_flags is ORed automatically into the flags;
43353 * the base flags mask typically prevents certain mark-and-sweep operations
43354 * to avoid trouble.
43355 */
43356
43357DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
43358 duk_hthread *thr;
43359 duk_size_t count_keep_obj;
43360 duk_size_t count_keep_str;
43361#ifdef DUK_USE_VOLUNTARY_GC
43362 duk_size_t tmp;
43363#endif
43364
43365 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43366 DUK_D(DUK_DPRINT("refuse to do a recursive mark-and-sweep"));
43367 return 0;
43368 }
43369
43370 /* XXX: thread selection for mark-and-sweep is currently a hack.
43371 * If we don't have a thread, the entire mark-and-sweep is now
43372 * skipped (although we could just skip finalizations).
43373 */
43374
43375 /* If thr != NULL, the thr may still be in the middle of
43376 * initialization.
43377 * XXX: Improve the thread viability test.
43378 */
43379 thr = duk__get_temp_hthread(heap);
43380 if (thr == NULL) {
43381 DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread"));
43382
43383 /* reset voluntary gc trigger count */
43384#ifdef DUK_USE_VOLUNTARY_GC
43385 heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP;
43386#endif
43387 return 0; /* OK */
43388 }
43389
43390 /* If debugger is paused, garbage collection is disabled by default. */
43391 /* XXX: will need a force flag if garbage collection is triggered
43392 * explicitly during paused state.
43393 */
43394#if defined(DUK_USE_DEBUGGER_SUPPORT)
43395 if (DUK_HEAP_IS_PAUSED(heap)) {
43396 /* Checking this here rather that in memory alloc primitives
43397 * reduces checking code there but means a failed allocation
43398 * will go through a few retries before giving up. That's
43399 * fine because this only happens during debugging.
43400 */
43401 DUK_D(DUK_DPRINT("gc skipped because debugger is paused"));
43402 return 0;
43403 }
43404#endif
43405
43406 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
43407 (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags)));
43408
43409 flags |= heap->mark_and_sweep_base_flags;
43410
43411 /*
43412 * Assertions before
43413 */
43414
43415#ifdef DUK_USE_ASSERTIONS
43416 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
43417 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
43418 DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
43419 duk__assert_heaphdr_flags(heap);
43420#ifdef DUK_USE_REFERENCE_COUNTING
43421 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
43422 * finalizer may trigger a mark-and-sweep.
43423 */
43424 duk__assert_valid_refcounts(heap);
43425#endif /* DUK_USE_REFERENCE_COUNTING */
43426#endif /* DUK_USE_ASSERTIONS */
43427
43428 /*
43429 * Begin
43430 */
43431
43432 DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
43433
43434 /*
43435 * Mark roots, hoping that recursion limit is not normally hit.
43436 * If recursion limit is hit, run additional reachability rounds
43437 * starting from "temproots" until marking is complete.
43438 *
43439 * Marking happens in two phases: first we mark actual reachability
43440 * roots (and run "temproots" to complete the process). Then we
43441 * check which objects are unreachable and are finalizable; such
43442 * objects are marked as FINALIZABLE and marked as reachability
43443 * (and "temproots" is run again to complete the process).
43444 *
43445 * The heap finalize_list must also be marked as a reachability root.
43446 * There may be objects on the list from a previous round if the
43447 * previous run had finalizer skip flag.
43448 */
43449
43450 duk__mark_roots_heap(heap); /* main reachability roots */
43451#ifdef DUK_USE_REFERENCE_COUNTING
43452 duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */
43453#endif
43454 duk__mark_temproots_by_heap_scan(heap); /* temproots */
43455
43456 duk__mark_finalizable(heap); /* mark finalizable as reachability roots */
43457 duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */
43458 duk__mark_temproots_by_heap_scan(heap); /* temproots */
43459
43460 /*
43461 * Sweep garbage and remove marking flags, and move objects with
43462 * finalizers to the finalizer work list.
43463 *
43464 * Objects to be swept need to get their refcounts finalized before
43465 * they are swept. In other words, their target object refcounts
43466 * need to be decreased. This has to be done before freeing any
43467 * objects to avoid decref'ing dangling pointers (which may happen
43468 * even without bugs, e.g. with reference loops)
43469 *
43470 * Because strings don't point to other heap objects, similar
43471 * finalization is not necessary for strings.
43472 */
43473
43474 /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
43475
43476#ifdef DUK_USE_REFERENCE_COUNTING
43477 duk__finalize_refcounts(heap);
43478#endif
43479 duk__sweep_heap(heap, flags, &count_keep_obj);
43480#if defined(DUK_USE_STRTAB_CHAIN)
43481 duk__sweep_stringtable_chain(heap, &count_keep_str);
43482#elif defined(DUK_USE_STRTAB_PROBE)
43483 duk__sweep_stringtable_probe(heap, &count_keep_str);
43484#else
43485#error internal error, invalid strtab options
43486#endif
43487#ifdef DUK_USE_REFERENCE_COUNTING
43488 duk__clear_refzero_list_flags(heap);
43489#endif
43490 duk__clear_finalize_list_flags(heap);
43491
43492 /*
43493 * Object compaction (emergency only).
43494 *
43495 * Object compaction is a separate step after sweeping, as there is
43496 * more free memory for it to work with. Also, currently compaction
43497 * may insert new objects into the heap allocated list and the string
43498 * table which we don't want to do during a sweep (the reachability
43499 * flags of such objects would be incorrect). The objects inserted
43500 * are currently:
43501 *
43502 * - a temporary duk_hbuffer for a new properties allocation
43503 * - if array part is abandoned, string keys are interned
43504 *
43505 * The object insertions go to the front of the list, so they do not
43506 * cause an infinite loop (they are not compacted).
43507 */
43508
43509 if ((flags & DUK_MS_FLAG_EMERGENCY) &&
43510 !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) {
43511 duk__compact_objects(heap);
43512 }
43513
43514 /*
43515 * String table resize check.
43516 *
43517 * Note: this may silently (and safely) fail if GC is caused by an
43518 * allocation call in stringtable resize_hash(). Resize_hash()
43519 * will prevent a recursive call to itself by setting the
43520 * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags.
43521 */
43522
43523 /* XXX: stringtable emergency compaction? */
43524
43525 /* XXX: remove this feature entirely? it would only matter for
43526 * emergency GC. Disable for lowest memory builds.
43527 */
43528#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
43529 if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) {
43530 DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap));
43531 duk_heap_force_strtab_resize(heap);
43532 } else {
43533 DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set"));
43534 }
43535#endif
43536
43537 /*
43538 * Finalize objects in the finalization work list. Finalized
43539 * objects are queued back to heap_allocated with FINALIZED set.
43540 *
43541 * Since finalizers may cause arbitrary side effects, they are
43542 * prevented during string table and object property allocation
43543 * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in
43544 * heap->mark_and_sweep_base_flags. In this case the objects
43545 * remain in the finalization work list after mark-and-sweep
43546 * exits and they may be finalized on the next pass.
43547 *
43548 * Finalization currently happens inside "MARKANDSWEEP_RUNNING"
43549 * protection (no mark-and-sweep may be triggered by the
43550 * finalizers). As a side effect:
43551 *
43552 * 1) an out-of-memory error inside a finalizer will not
43553 * cause a mark-and-sweep and may cause the finalizer
43554 * to fail unnecessarily
43555 *
43556 * 2) any temporary objects whose refcount decreases to zero
43557 * during finalization will not be put into refzero_list;
43558 * they can only be collected by another mark-and-sweep
43559 *
43560 * This is not optimal, but since the sweep for this phase has
43561 * already happened, this is probably good enough for now.
43562 */
43563
43564#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
43565 /* Cannot simulate individual finalizers because finalize_list only
43566 * contains objects with actual finalizers. But simulate side effects
43567 * from finalization by doing a bogus function call and resizing the
43568 * stacks.
43569 */
43570 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
43571 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set"));
43572 } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) {
43573 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable"));
43574 } else {
43575 DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer"));
43576 duk__markandsweep_torture_finalizer(thr);
43577 }
43578#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
43579
43580 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
43581 DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set"));
43582 } else {
43583 duk__run_object_finalizers(heap, flags);
43584 }
43585
43586 /*
43587 * Finish
43588 */
43589
43590 DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
43591
43592 /*
43593 * Assertions after
43594 */
43595
43596#ifdef DUK_USE_ASSERTIONS
43597 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
43598 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
43599 DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
43600 duk__assert_heaphdr_flags(heap);
43601#ifdef DUK_USE_REFERENCE_COUNTING
43602 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
43603 * finalizer may trigger a mark-and-sweep.
43604 */
43605 duk__assert_valid_refcounts(heap);
43606#endif /* DUK_USE_REFERENCE_COUNTING */
43607#endif /* DUK_USE_ASSERTIONS */
43608
43609 /*
43610 * Reset trigger counter
43611 */
43612
43613#ifdef DUK_USE_VOLUNTARY_GC
43614 tmp = (count_keep_obj + count_keep_str) / 256;
43615 heap->mark_and_sweep_trigger_counter = (duk_int_t) (
43616 (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
43617 DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD);
43618 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
43619 (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter));
43620#else
43621 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
43622 (long) count_keep_obj, (long) count_keep_str));
43623#endif
43624
43625 return 0; /* OK */
43626}
43627
43628#else /* DUK_USE_MARK_AND_SWEEP */
43629
43630/* no mark-and-sweep gc */
43631
43632#endif /* DUK_USE_MARK_AND_SWEEP */
43633#line 1 "duk_heap_memory.c"
43634/*
43635 * Memory allocation handling.
43636 */
43637
43638/* include removed: duk_internal.h */
43639
43640/*
43641 * Helpers
43642 *
43643 * The fast path checks are done within a macro to ensure "inlining"
43644 * while the slow path actions use a helper (which won't typically be
43645 * inlined in size optimized builds).
43646 */
43647
43648#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
43649#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \
43650 (heap)->mark_and_sweep_trigger_counter--; \
43651 if ((heap)->mark_and_sweep_trigger_counter <= 0) { \
43652 duk__run_voluntary_gc(heap); \
43653 } \
43654 } while (0)
43655
43656DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) {
43657 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43658 DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now"));
43659 } else {
43660 duk_small_uint_t flags;
43661 duk_bool_t rc;
43662
43663 DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep"));
43664 flags = 0;
43665 rc = duk_heap_mark_and_sweep(heap, flags);
43666 DUK_UNREF(rc);
43667 }
43668}
43669#else
43670#define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */
43671#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
43672
43673/*
43674 * Allocate memory with garbage collection
43675 */
43676
43677#ifdef DUK_USE_MARK_AND_SWEEP
43678DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
43679 void *res;
43680 duk_bool_t rc;
43681 duk_small_int_t i;
43682
43683 DUK_ASSERT(heap != NULL);
43684 DUK_ASSERT_DISABLE(size >= 0);
43685
43686 /*
43687 * Voluntary periodic GC (if enabled)
43688 */
43689
43690 DUK__VOLUNTARY_PERIODIC_GC(heap);
43691
43692 /*
43693 * First attempt
43694 */
43695
43696#ifdef DUK_USE_GC_TORTURE
43697 /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */
43698 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43699 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
43700 res = NULL;
43701 DUK_UNREF(res);
43702 goto skip_attempt;
43703 }
43704#endif
43705 res = heap->alloc_func(heap->heap_udata, size);
43706 if (res || size == 0) {
43707 /* for zero size allocations NULL is allowed */
43708 return res;
43709 }
43710#ifdef DUK_USE_GC_TORTURE
43711 skip_attempt:
43712#endif
43713
43714 DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
43715
43716 /*
43717 * Avoid a GC if GC is already running. This can happen at a late
43718 * stage in a GC when we try to e.g. resize the stringtable
43719 * or compact objects.
43720 */
43721
43722 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43723 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
43724 return NULL;
43725 }
43726
43727 /*
43728 * Retry with several GC attempts. Initial attempts are made without
43729 * emergency mode; later attempts use emergency mode which minimizes
43730 * memory allocations forcibly.
43731 */
43732
43733 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
43734 duk_small_uint_t flags;
43735
43736 flags = 0;
43737 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
43738 flags |= DUK_MS_FLAG_EMERGENCY;
43739 }
43740
43741 rc = duk_heap_mark_and_sweep(heap, flags);
43742 DUK_UNREF(rc);
43743
43744 res = heap->alloc_func(heap->heap_udata, size);
43745 if (res) {
43746 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld",
43747 (long) (i + 1), (long) size));
43748 return res;
43749 }
43750 }
43751
43752 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
43753 return NULL;
43754}
43755#else /* DUK_USE_MARK_AND_SWEEP */
43756/*
43757 * Compared to a direct macro expansion this wrapper saves a few
43758 * instructions because no heap dereferencing is required.
43759 */
43760DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
43761 DUK_ASSERT(heap != NULL);
43762 DUK_ASSERT_DISABLE(size >= 0);
43763
43764 return heap->alloc_func(heap->heap_udata, size);
43765}
43766#endif /* DUK_USE_MARK_AND_SWEEP */
43767
43768DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
43769 void *res;
43770
43771 DUK_ASSERT(heap != NULL);
43772 DUK_ASSERT_DISABLE(size >= 0);
43773
43774 res = DUK_ALLOC(heap, size);
43775 if (res) {
43776 /* assume memset with zero size is OK */
43777 DUK_MEMZERO(res, size);
43778 }
43779 return res;
43780}
43781
43782/*
43783 * Reallocate memory with garbage collection
43784 */
43785
43786#ifdef DUK_USE_MARK_AND_SWEEP
43787DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
43788 void *res;
43789 duk_bool_t rc;
43790 duk_small_int_t i;
43791
43792 DUK_ASSERT(heap != NULL);
43793 /* ptr may be 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 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, ptr, 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 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() 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 flags = 0;
43845 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
43846 flags |= DUK_MS_FLAG_EMERGENCY;
43847 }
43848
43849 rc = duk_heap_mark_and_sweep(heap, flags);
43850 DUK_UNREF(rc);
43851
43852 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
43853 if (res || newsize == 0) {
43854 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld",
43855 (long) (i + 1), (long) newsize));
43856 return res;
43857 }
43858 }
43859
43860 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
43861 return NULL;
43862}
43863#else /* DUK_USE_MARK_AND_SWEEP */
43864/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
43865DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
43866 DUK_ASSERT(heap != NULL);
43867 /* ptr may be NULL */
43868 DUK_ASSERT_DISABLE(newsize >= 0);
43869
43870 return heap->realloc_func(heap->heap_udata, ptr, newsize);
43871}
43872#endif /* DUK_USE_MARK_AND_SWEEP */
43873
43874/*
43875 * Reallocate memory with garbage collection, using a callback to provide
43876 * the current allocated pointer. This variant is used when a mark-and-sweep
43877 * (e.g. finalizers) might change the original pointer.
43878 */
43879
43880#ifdef DUK_USE_MARK_AND_SWEEP
43881DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
43882 void *res;
43883 duk_bool_t rc;
43884 duk_small_int_t i;
43885
43886 DUK_ASSERT(heap != NULL);
43887 DUK_ASSERT_DISABLE(newsize >= 0);
43888
43889 /*
43890 * Voluntary periodic GC (if enabled)
43891 */
43892
43893 DUK__VOLUNTARY_PERIODIC_GC(heap);
43894
43895 /*
43896 * First attempt
43897 */
43898
43899#ifdef DUK_USE_GC_TORTURE
43900 /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
43901 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43902 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
43903 res = NULL;
43904 DUK_UNREF(res);
43905 goto skip_attempt;
43906 }
43907#endif
43908 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
43909 if (res || newsize == 0) {
43910 /* for zero size allocations NULL is allowed */
43911 return res;
43912 }
43913#ifdef DUK_USE_GC_TORTURE
43914 skip_attempt:
43915#endif
43916
43917 DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
43918
43919 /*
43920 * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
43921 */
43922
43923 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43924 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
43925 return NULL;
43926 }
43927
43928 /*
43929 * Retry with several GC attempts. Initial attempts are made without
43930 * emergency mode; later attempts use emergency mode which minimizes
43931 * memory allocations forcibly.
43932 */
43933
43934 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
43935 duk_small_uint_t flags;
43936
43937#ifdef DUK_USE_ASSERTIONS
43938 void *ptr_pre; /* ptr before mark-and-sweep */
43939 void *ptr_post;
43940#endif
43941
43942#ifdef DUK_USE_ASSERTIONS
43943 ptr_pre = cb(heap, ud);
43944#endif
43945 flags = 0;
43946 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
43947 flags |= DUK_MS_FLAG_EMERGENCY;
43948 }
43949
43950 rc = duk_heap_mark_and_sweep(heap, flags);
43951 DUK_UNREF(rc);
43952#ifdef DUK_USE_ASSERTIONS
43953 ptr_post = cb(heap, ud);
43954 if (ptr_pre != ptr_post) {
43955 /* useful for debugging */
43956 DUK_DD(DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p",
43957 (void *) ptr_pre, (void *) ptr_post));
43958 }
43959#endif
43960
43961 /* Note: key issue here is to re-lookup the base pointer on every attempt.
43962 * The pointer being reallocated may change after every mark-and-sweep.
43963 */
43964
43965 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
43966 if (res || newsize == 0) {
43967 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld",
43968 (long) (i + 1), (long) newsize));
43969 return res;
43970 }
43971 }
43972
43973 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
43974 return NULL;
43975}
43976#else /* DUK_USE_MARK_AND_SWEEP */
43977/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
43978DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
43979 return heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
43980}
43981#endif /* DUK_USE_MARK_AND_SWEEP */
43982
43983/*
43984 * Free memory
43985 */
43986
43987#ifdef DUK_USE_MARK_AND_SWEEP
43988DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
43989 DUK_ASSERT(heap != NULL);
43990 /* ptr may be NULL */
43991
43992 /* Must behave like a no-op with NULL and any pointer returned from
43993 * malloc/realloc with zero size.
43994 */
43995 heap->free_func(heap->heap_udata, ptr);
43996
43997 /* Count free operations toward triggering a GC but never actually trigger
43998 * a GC from a free. Otherwise code which frees internal structures would
43999 * need to put in NULLs at every turn to ensure the object is always in
44000 * consistent state for a mark-and-sweep.
44001 */
44002#ifdef DUK_USE_VOLUNTARY_GC
44003 heap->mark_and_sweep_trigger_counter--;
44004#endif
44005}
44006#else
44007/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
44008DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
44009 DUK_ASSERT(heap != NULL);
44010 /* ptr may be NULL */
44011
44012 /* Note: must behave like a no-op with NULL and any pointer
44013 * returned from malloc/realloc with zero size.
44014 */
44015 heap->free_func(heap->heap_udata, ptr);
44016}
44017#endif
44018#line 1 "duk_heap_misc.c"
44019/*
44020 * Support functions for duk_heap.
44021 */
44022
44023/* include removed: duk_internal.h */
44024
44025#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
44026/* arbitrary remove only works with double linked heap, and is only required by
44027 * reference counting so far.
44028 */
44029DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
44030 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
44031
44032 if (DUK_HEAPHDR_GET_PREV(heap, hdr)) {
44033 DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr));
44034 } else {
44035 heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44036 }
44037 if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) {
44038 DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr));
44039 } else {
44040 ;
44041 }
44042
44043 /* The prev/next pointers of the removed duk_heaphdr are left as garbage.
44044 * It's up to the caller to ensure they're written before inserting the
44045 * object back.
44046 */
44047}
44048#endif
44049
44050DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
44051 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
44052
44053#ifdef DUK_USE_DOUBLE_LINKED_HEAP
44054 if (heap->heap_allocated) {
44055 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL);
44056 DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr);
44057 }
44058 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
44059#endif
44060 DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated);
44061 heap->heap_allocated = hdr;
44062}
44063
44064#ifdef DUK_USE_INTERRUPT_COUNTER
44065DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
44066 duk_hthread *curr_thr;
44067
44068 DUK_ASSERT(heap != NULL);
44069
44070 if (new_thr != NULL) {
44071 curr_thr = heap->curr_thread;
44072 if (curr_thr == NULL) {
44073 /* For initial entry use default value; zero forces an
44074 * interrupt before executing the first insturction.
44075 */
44076 DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter"));
44077 new_thr->interrupt_counter = 0;
44078 new_thr->interrupt_init = 0;
44079 } else {
44080 /* Copy interrupt counter/init value state to new thread (if any).
44081 * It's OK for new_thr to be the same as curr_thr.
44082 */
44083#if defined(DUK_USE_DEBUG)
44084 if (new_thr != curr_thr) {
44085 DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter"));
44086 }
44087#endif
44088 new_thr->interrupt_counter = curr_thr->interrupt_counter;
44089 new_thr->interrupt_init = curr_thr->interrupt_init;
44090 }
44091 } else {
44092 DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes"));
44093 }
44094
44095 heap->curr_thread = new_thr; /* may be NULL */
44096}
44097#endif /* DUK_USE_INTERRUPT_COUNTER */
44098#line 1 "duk_heap_refcount.c"
44099/*
44100 * Reference counting implementation.
44101 */
44102
44103/* include removed: duk_internal.h */
44104
44105#ifdef DUK_USE_REFERENCE_COUNTING
44106
44107#ifndef DUK_USE_DOUBLE_LINKED_HEAP
44108#error internal error, reference counting requires a double linked heap
44109#endif
44110
44111/*
44112 * Misc
44113 */
44114
44115DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) {
44116 /* tail insert: don't disturb head in case refzero is running */
44117
44118 if (heap->refzero_list != NULL) {
44119 duk_heaphdr *hdr_prev;
44120
44121 hdr_prev = heap->refzero_list_tail;
44122 DUK_ASSERT(hdr_prev != NULL);
44123 DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL);
44124
44125 DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
44126 DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev);
44127 DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr);
44128 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
44129 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev);
44130 heap->refzero_list_tail = hdr;
44131 } else {
44132 DUK_ASSERT(heap->refzero_list_tail == NULL);
44133 DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
44134 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
44135 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
44136 heap->refzero_list = hdr;
44137 heap->refzero_list_tail = hdr;
44138 }
44139}
44140
44141/*
44142 * Heap object refcount finalization.
44143 *
44144 * When an object is about to be freed, all other objects it refers to must
44145 * be decref'd. Refcount finalization does NOT free the object or its inner
44146 * allocations (mark-and-sweep shares these helpers), it just manipulates
44147 * the refcounts.
44148 *
44149 * Note that any of the decref's may cause a refcount to drop to zero, BUT
44150 * it will not be processed inline; instead, because refzero is already
44151 * running, the objects will just be queued to refzero list and processed
44152 * later. This eliminates C recursion.
44153 */
44154
44155DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
44156 duk_uint_fast32_t i;
44157
44158 DUK_ASSERT(h);
44159 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
44160
44161 /* XXX: better to get base and walk forwards? */
44162
44163 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
44164 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
44165 if (!key) {
44166 continue;
44167 }
44168 duk_heaphdr_decref(thr, (duk_heaphdr *) key);
44169 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)) {
44170 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, h, i));
44171 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, h, i));
44172 } else {
44173 duk_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i));
44174 }
44175 }
44176
44177 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
44178 duk_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i));
44179 }
44180
44181 /* hash part is a 'weak reference' and does not contribute */
44182
44183 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h));
44184
44185 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
44186 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
44187 duk_tval *tv, *tv_end;
44188 duk_hobject **funcs, **funcs_end;
44189
44190 if (DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL) {
44191 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
44192 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
44193 while (tv < tv_end) {
44194 duk_tval_decref(thr, tv);
44195 tv++;
44196 }
44197
44198 funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
44199 funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
44200 while (funcs < funcs_end) {
44201 duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
44202 funcs++;
44203 }
44204 } else {
44205 /* May happen in some out-of-memory corner cases. */
44206 DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping decref"));
44207 }
44208
44209 duk_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f));
44210 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
44211 duk_hnativefunction *f = (duk_hnativefunction *) h;
44212 DUK_UNREF(f);
44213 /* nothing to finalize */
44214 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
44215 duk_hbufferobject *b = (duk_hbufferobject *) h;
44216 if (b->buf) {
44217 duk_heaphdr_decref(thr, (duk_heaphdr *) b->buf);
44218 }
44219 } else if (DUK_HOBJECT_IS_THREAD(h)) {
44220 duk_hthread *t = (duk_hthread *) h;
44221 duk_tval *tv;
44222
44223 tv = t->valstack;
44224 while (tv < t->valstack_top) {
44225 duk_tval_decref(thr, tv);
44226 tv++;
44227 }
44228
44229 for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
44230 duk_activation *act = t->callstack + i;
44231 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
44232 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->var_env);
44233 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->lex_env);
44234#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
44235 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->prev_caller);
44236#endif
44237 }
44238
44239#if 0 /* nothing now */
44240 for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
44241 duk_catcher *cat = t->catchstack + i;
44242 }
44243#endif
44244
44245 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
44246 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->builtins[i]);
44247 }
44248
44249 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->resumer);
44250 }
44251}
44252
44253DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr) {
44254 DUK_ASSERT(hdr);
44255
44256 switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
44257 case DUK_HTYPE_OBJECT:
44258 duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr);
44259 break;
44260 case DUK_HTYPE_BUFFER:
44261 /* nothing to finalize */
44262 break;
44263 case DUK_HTYPE_STRING:
44264 /* cannot happen: strings are not put into refzero list (they don't even have the next/prev pointers) */
44265 default:
44266 DUK_UNREACHABLE();
44267 }
44268}
44269
44270#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
44271DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) {
44272 DUK_UNREF(ctx);
44273 DUK_D(DUK_DPRINT("fake refcount torture finalizer executed"));
44274#if 0
44275 DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0)));
44276#endif
44277 /* Require a lot of stack to force a value stack grow/shrink. */
44278 duk_require_stack(ctx, 100000);
44279
44280 /* XXX: do something to force a callstack grow/shrink, perhaps
44281 * just a manual forced resize?
44282 */
44283 return 0;
44284}
44285
44286DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) {
44287 duk_context *ctx;
44288 duk_int_t rc;
44289
44290 DUK_ASSERT(thr != NULL);
44291 DUK_ASSERT(obj != NULL);
44292 ctx = (duk_context *) thr;
44293
44294 /* Avoid fake finalization for the duk__refcount_fake_finalizer function
44295 * itself, otherwise we're in infinite recursion.
44296 */
44297 if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
44298 if (((duk_hnativefunction *) obj)->func == duk__refcount_fake_finalizer) {
44299 DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself"));
44300 return;
44301 }
44302 }
44303 /* Avoid fake finalization when callstack limit has been reached.
44304 * Otherwise a callstack limit error will be created, then refzero'ed,
44305 * and we're in an infinite loop.
44306 */
44307 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
44308 thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
44309 DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer"));
44310 return;
44311 }
44312
44313 /* Run fake finalizer. Avoid creating new refzero queue entries
44314 * so that we are not forced into a forever loop.
44315 */
44316 duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/);
44317 duk_push_hobject(ctx, obj);
44318 rc = duk_pcall(ctx, 1);
44319 DUK_UNREF(rc); /* ignored */
44320 duk_pop(ctx);
44321}
44322#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
44323
44324/*
44325 * Refcount memory freeing loop.
44326 *
44327 * Frees objects in the refzero_pending list until the list becomes
44328 * empty. When an object is freed, its references get decref'd and
44329 * may cause further objects to be queued for freeing.
44330 *
44331 * This could be expanded to allow incremental freeing: just bail out
44332 * early and resume at a future alloc/decref/refzero.
44333 */
44334
44335DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
44336 duk_heaphdr *h1, *h2;
44337 duk_heap *heap;
44338 duk_int_t count = 0;
44339
44340 DUK_ASSERT(thr != NULL);
44341 DUK_ASSERT(thr->heap != NULL);
44342 heap = thr->heap;
44343 DUK_ASSERT(heap != NULL);
44344
44345 /*
44346 * Detect recursive invocation
44347 */
44348
44349 if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) {
44350 DUK_DDD(DUK_DDDPRINT("refzero free running, skip run"));
44351 return;
44352 }
44353
44354 /*
44355 * Churn refzero_list until empty
44356 */
44357
44358 DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap);
44359 while (heap->refzero_list) {
44360 duk_hobject *obj;
44361 duk_bool_t rescued = 0;
44362
44363 /*
44364 * Pick an object from the head (don't remove yet).
44365 */
44366
44367 h1 = heap->refzero_list;
44368 obj = (duk_hobject *) h1;
44369 DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1));
44370 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL);
44371 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */
44372
44373#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
44374 /* Torture option to shake out finalizer side effect issues:
44375 * make a bogus function call for every finalizable object,
44376 * essentially simulating the case where everything has a
44377 * finalizer.
44378 */
44379 DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer"));
44380 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
44381 DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
44382 duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */
44383 DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
44384 DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
44385#endif
44386
44387 /*
44388 * Finalizer check.
44389 *
44390 * Note: running a finalizer may have arbitrary side effects, e.g.
44391 * queue more objects on refzero_list (tail), or even trigger a
44392 * mark-and-sweep.
44393 *
44394 * Note: quick reject check should match vast majority of
44395 * objects and must be safe (not throw any errors, ever).
44396 */
44397
44398 /* An object may have FINALIZED here if it was finalized by mark-and-sweep
44399 * on a previous run and refcount then decreased to zero. We won't run the
44400 * finalizer again here.
44401 */
44402
44403 /* A finalizer is looked up from the object and up its prototype chain
44404 * (which allows inherited finalizers).
44405 */
44406 if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
44407 DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it"));
44408
44409 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
44410 DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
44411
44412 duk_hobject_run_finalizer(thr, obj); /* must never longjmp */
44413 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */
44414
44415 DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
44416 DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
44417
44418 if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) {
44419 DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued"));
44420 rescued = 1;
44421 } else {
44422 DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed"));
44423 }
44424 }
44425
44426 /* Refzero head is still the same. This is the case even if finalizer
44427 * inserted more refzero objects; they are inserted to the tail.
44428 */
44429 DUK_ASSERT(h1 == heap->refzero_list);
44430
44431 /*
44432 * Remove the object from the refzero list. This cannot be done
44433 * before a possible finalizer has been executed; the finalizer
44434 * may trigger a mark-and-sweep, and mark-and-sweep must be able
44435 * to traverse a complete refzero_list.
44436 */
44437
44438 h2 = DUK_HEAPHDR_GET_NEXT(heap, h1);
44439 if (h2) {
44440 DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */
44441 heap->refzero_list = h2;
44442 } else {
44443 heap->refzero_list = NULL;
44444 heap->refzero_list_tail = NULL;
44445 }
44446
44447 /*
44448 * Rescue or free.
44449 */
44450
44451 if (rescued) {
44452 /* yes -> move back to heap allocated */
44453 DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1));
44454 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1));
44455 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1));
44456 DUK_HEAPHDR_CLEAR_FINALIZED(h1);
44457 h2 = heap->heap_allocated;
44458 DUK_HEAPHDR_SET_PREV(heap, h1, NULL);
44459 if (h2) {
44460 DUK_HEAPHDR_SET_PREV(heap, h2, h1);
44461 }
44462 DUK_HEAPHDR_SET_NEXT(heap, h1, h2);
44463 DUK_ASSERT_HEAPHDR_LINKS(heap, h1);
44464 DUK_ASSERT_HEAPHDR_LINKS(heap, h2);
44465 heap->heap_allocated = h1;
44466 } else {
44467 /* no -> decref members, then free */
44468 duk__refcount_finalize_hobject(thr, obj);
44469 duk_heap_free_heaphdr_raw(heap, h1);
44470 }
44471
44472 count++;
44473 }
44474 DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap);
44475
44476 DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count));
44477
44478 /*
44479 * Once the whole refzero cascade has been freed, check for
44480 * a voluntary mark-and-sweep.
44481 */
44482
44483#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
44484 /* 'count' is more or less comparable to normal trigger counter update
44485 * which happens in memory block (re)allocation.
44486 */
44487 heap->mark_and_sweep_trigger_counter -= count;
44488 if (heap->mark_and_sweep_trigger_counter <= 0) {
44489 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
44490 DUK_D(DUK_DPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now"));
44491 } else {
44492 duk_bool_t rc;
44493 duk_small_uint_t flags = 0; /* not emergency */
44494 DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep"));
44495 rc = duk_heap_mark_and_sweep(heap, flags);
44496 DUK_UNREF(rc);
44497 DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc));
44498 }
44499 }
44500#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
44501}
44502
44503/*
44504 * Incref and decref functions.
44505 *
44506 * Decref may trigger immediate refzero handling, which may free and finalize
44507 * an arbitrary number of objects.
44508 *
44509 */
44510
44511DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
44512 duk_heap *heap;
44513
44514 DUK_ASSERT(thr != NULL);
44515 DUK_ASSERT(h != NULL);
44516
44517 heap = thr->heap;
44518 DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h));
44519
44520 /*
44521 * Refzero handling is skipped entirely if (1) mark-and-sweep is
44522 * running or (2) execution is paused in the debugger. The objects
44523 * are left in the heap, and will be freed by mark-and-sweep or
44524 * eventual heap destruction.
44525 *
44526 * This is necessary during mark-and-sweep because refcounts are also
44527 * updated during the sweep phase (otherwise objects referenced by a
44528 * swept object would have incorrect refcounts) which then calls here.
44529 * This could be avoided by using separate decref macros in
44530 * mark-and-sweep; however, mark-and-sweep also calls finalizers which
44531 * would use the ordinary decref macros anyway and still call this
44532 * function.
44533 *
44534 * This check must be enabled also when mark-and-sweep support has been
44535 * disabled: the flag is also used in heap destruction when running
44536 * finalizers for remaining objects, and the flag prevents objects from
44537 * being moved around in heap linked lists.
44538 */
44539
44540 /* XXX: ideally this would be just one flag (maybe a derived one) so
44541 * that a single bit test is sufficient to check the condition.
44542 */
44543#if defined(DUK_USE_DEBUGGER_SUPPORT)
44544 if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap))) {
44545#else
44546 if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))) {
44547#endif
44548 DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h));
44549 return;
44550 }
44551
44552 switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
44553 case DUK_HTYPE_STRING:
44554 /*
44555 * Strings have no internal references but do have "weak"
44556 * references in the string cache. Also note that strings
44557 * are not on the heap_allocated list like other heap
44558 * elements.
44559 */
44560
44561 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
44562 duk_heap_string_remove(heap, (duk_hstring *) h);
44563 duk_heap_free_heaphdr_raw(heap, h);
44564 break;
44565
44566 case DUK_HTYPE_OBJECT:
44567 /*
44568 * Objects have internal references. Must finalize through
44569 * the "refzero" work list.
44570 */
44571
44572 duk_heap_remove_any_from_heap_allocated(heap, h);
44573 duk__queue_refzero(heap, h);
44574 duk__refzero_free_pending(thr);
44575 break;
44576
44577 case DUK_HTYPE_BUFFER:
44578 /*
44579 * Buffers have no internal references. However, a dynamic
44580 * buffer has a separate allocation for the buffer. This is
44581 * freed by duk_heap_free_heaphdr_raw().
44582 */
44583
44584 duk_heap_remove_any_from_heap_allocated(heap, h);
44585 duk_heap_free_heaphdr_raw(heap, h);
44586 break;
44587
44588 default:
44589 DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h)));
44590 DUK_UNREACHABLE();
44591 }
44592}
44593
44594#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
44595DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
44596 DUK_ASSERT(tv != NULL);
44597
44598 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
44599 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44600 DUK_ASSERT(h != NULL);
44601 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44602 DUK_ASSERT_DISABLE(h->h_refcount >= 0);
44603 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44604 }
44605}
44606#endif
44607
44608#if 0 /* unused */
44609DUK_INTERNAL void duk_tval_incref_allownull(duk_tval *tv) {
44610 if (tv == NULL) {
44611 return;
44612 }
44613 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
44614 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44615 DUK_ASSERT(h != NULL);
44616 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44617 DUK_ASSERT_DISABLE(h->h_refcount >= 0);
44618 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44619 }
44620}
44621#endif
44622
44623DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
44624 DUK_ASSERT(thr != NULL);
44625 DUK_ASSERT(tv != NULL);
44626
44627 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
44628 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44629 DUK_ASSERT(h != NULL);
44630 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44631 duk_heaphdr_decref(thr, h);
44632 }
44633}
44634
44635#if 0 /* unused */
44636DUK_INTERNAL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv) {
44637 DUK_ASSERT(thr != NULL);
44638
44639 if (tv == NULL) {
44640 return;
44641 }
44642 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
44643 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44644 DUK_ASSERT(h != NULL);
44645 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44646 duk_heaphdr_decref(thr, h);
44647 }
44648}
44649#endif
44650
44651#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
44652DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
44653 DUK_ASSERT(h != NULL);
44654 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44655 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
44656
44657#if defined(DUK_USE_ROM_OBJECTS)
44658 if (DUK_HEAPHDR_HAS_READONLY(h)) {
44659 return;
44660 }
44661#endif
44662
44663 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44664}
44665#endif
44666
44667#if 0 /* unused */
44668DUK_INTERNAL void duk_heaphdr_incref_allownull(duk_heaphdr *h) {
44669 if (h == NULL) {
44670 return;
44671 }
44672 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44673 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
44674
44675 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44676}
44677#endif
44678
44679DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
44680 DUK_ASSERT(thr != NULL);
44681 DUK_ASSERT(thr->heap != NULL);
44682 DUK_ASSERT(h != NULL);
44683 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44684 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
44685
44686#if defined(DUK_USE_ROM_OBJECTS)
44687 if (DUK_HEAPHDR_HAS_READONLY(h)) {
44688 return;
44689 }
44690#endif
44691 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
44692 return;
44693 }
44694 duk_heaphdr_refzero(thr, h);
44695}
44696
44697DUK_INTERNAL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h) {
44698 DUK_ASSERT(thr != NULL);
44699 DUK_ASSERT(thr->heap != NULL);
44700
44701 if (h == NULL) {
44702 return;
44703 }
44704 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44705
44706#if defined(DUK_USE_ROM_OBJECTS)
44707 if (DUK_HEAPHDR_HAS_READONLY(h)) {
44708 return;
44709 }
44710#endif
44711 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
44712 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
44713 return;
44714 }
44715 duk_heaphdr_refzero(thr, h);
44716}
44717
44718#else
44719
44720/* no refcounting */
44721
44722#endif /* DUK_USE_REFERENCE_COUNTING */
44723#line 1 "duk_heap_stringcache.c"
44724/*
44725 * String cache.
44726 *
44727 * Provides a cache to optimize indexed string lookups. The cache keeps
44728 * track of (byte offset, char offset) states for a fixed number of strings.
44729 * Otherwise we'd need to scan from either end of the string, as we store
44730 * strings in (extended) UTF-8.
44731 */
44732
44733/* include removed: duk_internal.h */
44734
44735/*
44736 * Delete references to given hstring from the heap string cache.
44737 *
44738 * String cache references are 'weak': they are not counted towards
44739 * reference counts, nor serve as roots for mark-and-sweep. When an
44740 * object is about to be freed, such references need to be removed.
44741 */
44742
44743DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
44744 duk_small_int_t i;
44745 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44746 duk_strcache *c = heap->strcache + i;
44747 if (c->h == h) {
44748 DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
44749 (void *) h, (void *) heap));
44750 c->h = NULL;
44751
44752 /* XXX: the string shouldn't appear twice, but we now loop to the
44753 * end anyway; if fixed, add a looping assertion to ensure there
44754 * is no duplicate.
44755 */
44756 }
44757 }
44758}
44759
44760/*
44761 * String scanning helpers
44762 *
44763 * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
44764 * considered to contribute a character. This must match how string
44765 * character length is computed.
44766 */
44767
44768DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
44769 while (n > 0) {
44770 for (;;) {
44771 p++;
44772 if (p >= q) {
44773 return NULL;
44774 }
44775 if ((*p & 0xc0) != 0x80) {
44776 break;
44777 }
44778 }
44779 n--;
44780 }
44781 return p;
44782}
44783
44784DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
44785 while (n > 0) {
44786 for (;;) {
44787 p--;
44788 if (p < q) {
44789 return NULL;
44790 }
44791 if ((*p & 0xc0) != 0x80) {
44792 break;
44793 }
44794 }
44795 n--;
44796 }
44797 return p;
44798}
44799
44800/*
44801 * Convert char offset to byte offset
44802 *
44803 * Avoid using the string cache if possible: for ASCII strings byte and
44804 * char offsets are equal and for short strings direct scanning may be
44805 * better than using the string cache (which may evict a more important
44806 * entry).
44807 *
44808 * Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
44809 * Better typing might be to use duk_size_t.
44810 */
44811
44812DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
44813 duk_heap *heap;
44814 duk_strcache *sce;
44815 duk_uint_fast32_t byte_offset;
44816 duk_small_int_t i;
44817 duk_bool_t use_cache;
44818 duk_uint_fast32_t dist_start, dist_end, dist_sce;
44819 const duk_uint8_t *p_start;
44820 const duk_uint8_t *p_end;
44821 const duk_uint8_t *p_found;
44822
44823 if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
44824 goto error;
44825 }
44826
44827 /*
44828 * For ASCII strings, the answer is simple.
44829 */
44830
44831 if (DUK_HSTRING_IS_ASCII(h)) {
44832 /* clen == blen -> pure ascii */
44833 return char_offset;
44834 }
44835
44836 /*
44837 * For non-ASCII strings, we need to scan forwards or backwards
44838 * from some starting point. The starting point may be the start
44839 * or end of the string, or some cached midpoint in the string
44840 * cache.
44841 *
44842 * For "short" strings we simply scan without checking or updating
44843 * the cache. For longer strings we check and update the cache as
44844 * necessary, inserting a new cache entry if none exists.
44845 */
44846
44847 DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
44848 (void *) h, (long) char_offset,
44849 (long) DUK_HSTRING_GET_CHARLEN(h),
44850 (long) DUK_HSTRING_GET_BYTELEN(h)));
44851
44852 heap = thr->heap;
44853 sce = NULL;
44854 use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
44855
44856 if (use_cache) {
44857#ifdef DUK_USE_DDDPRINT
44858 DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
44859 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44860 duk_strcache *c = heap->strcache + i;
44861 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
44862 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
44863 }
44864#endif
44865
44866 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44867 duk_strcache *c = heap->strcache + i;
44868
44869 if (c->h == h) {
44870 sce = c;
44871 break;
44872 }
44873 }
44874 }
44875
44876 /*
44877 * Scan from shortest distance:
44878 * - start of string
44879 * - end of string
44880 * - cache entry (if exists)
44881 */
44882
44883 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
44884 dist_start = char_offset;
44885 dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
44886 dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
44887
44888 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
44889 p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
44890 p_found = NULL;
44891
44892 if (sce) {
44893 if (char_offset >= sce->cidx) {
44894 dist_sce = char_offset - sce->cidx;
44895 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
44896 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44897 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44898 "scan forwards from sce",
44899 (long) use_cache, (void *) (sce ? sce->h : NULL),
44900 (sce ? (long) sce->cidx : (long) -1),
44901 (sce ? (long) sce->bidx : (long) -1),
44902 (long) dist_start, (long) dist_end, (long) dist_sce));
44903
44904 p_found = duk__scan_forwards(p_start + sce->bidx,
44905 p_end,
44906 dist_sce);
44907 goto scan_done;
44908 }
44909 } else {
44910 dist_sce = sce->cidx - char_offset;
44911 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
44912 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44913 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44914 "scan backwards from sce",
44915 (long) use_cache, (void *) (sce ? sce->h : NULL),
44916 (sce ? (long) sce->cidx : (long) -1),
44917 (sce ? (long) sce->bidx : (long) -1),
44918 (long) dist_start, (long) dist_end, (long) dist_sce));
44919
44920 p_found = duk__scan_backwards(p_start + sce->bidx,
44921 p_start,
44922 dist_sce);
44923 goto scan_done;
44924 }
44925 }
44926 }
44927
44928 /* no sce, or sce scan not best */
44929
44930 if (dist_start <= dist_end) {
44931 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44932 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44933 "scan forwards from string start",
44934 (long) use_cache, (void *) (sce ? sce->h : NULL),
44935 (sce ? (long) sce->cidx : (long) -1),
44936 (sce ? (long) sce->bidx : (long) -1),
44937 (long) dist_start, (long) dist_end, (long) dist_sce));
44938
44939 p_found = duk__scan_forwards(p_start,
44940 p_end,
44941 dist_start);
44942 } else {
44943 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44944 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44945 "scan backwards from string end",
44946 (long) use_cache, (void *) (sce ? sce->h : NULL),
44947 (sce ? (long) sce->cidx : (long) -1),
44948 (sce ? (long) sce->bidx : (long) -1),
44949 (long) dist_start, (long) dist_end, (long) dist_sce));
44950
44951 p_found = duk__scan_backwards(p_end,
44952 p_start,
44953 dist_end);
44954 }
44955
44956 scan_done:
44957
44958 if (!p_found) {
44959 /* Scan error: this shouldn't normally happen; it could happen if
44960 * string is not valid UTF-8 data, and clen/blen are not consistent
44961 * with the scanning algorithm.
44962 */
44963 goto error;
44964 }
44965
44966 DUK_ASSERT(p_found >= p_start);
44967 DUK_ASSERT(p_found <= p_end); /* may be equal */
44968 byte_offset = (duk_uint32_t) (p_found - p_start);
44969
44970 DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
44971 (void *) h, (long) char_offset, (long) byte_offset));
44972
44973 /*
44974 * Update cache entry (allocating if necessary), and move the
44975 * cache entry to the first place (in an "LRU" policy).
44976 */
44977
44978 if (use_cache) {
44979 /* update entry, allocating if necessary */
44980 if (!sce) {
44981 sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */
44982 sce->h = h;
44983 }
44984 DUK_ASSERT(sce != NULL);
44985 sce->bidx = (duk_uint32_t) (p_found - p_start);
44986 sce->cidx = (duk_uint32_t) char_offset;
44987
44988 /* LRU: move our entry to first */
44989 if (sce > &heap->strcache[0]) {
44990 /*
44991 * A C
44992 * B A
44993 * C <- sce ==> B
44994 * D D
44995 */
44996 duk_strcache tmp;
44997
44998 tmp = *sce;
44999 DUK_MEMMOVE((void *) (&heap->strcache[1]),
45000 (const void *) (&heap->strcache[0]),
45001 (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
45002 heap->strcache[0] = tmp;
45003
45004 /* 'sce' points to the wrong entry here, but is no longer used */
45005 }
45006#ifdef DUK_USE_DDDPRINT
45007 DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
45008 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
45009 duk_strcache *c = heap->strcache + i;
45010 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
45011 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
45012 }
45013#endif
45014 }
45015
45016 return byte_offset;
45017
45018 error:
45019 DUK_ERROR_INTERNAL_DEFMSG(thr);
45020 return 0;
45021}
45022#line 1 "duk_heap_stringtable.c"
45023/*
45024 * Heap stringtable handling, string interning.
45025 */
45026
45027/* include removed: duk_internal.h */
45028
45029#if defined(DUK_USE_STRTAB_PROBE)
45030#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size))
45031#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash))
45032#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap))
45033#endif
45034
45035#if defined(DUK_USE_MARK_AND_SWEEP)
45036#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \
45037 (heap)->mark_and_sweep_base_flags |= \
45038 DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \
45039 DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \
45040 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \
45041 } while (0)
45042#endif
45043
45044/*
45045 * Create a hstring and insert into the heap. The created object
45046 * is directly garbage collectable with reference count zero.
45047 *
45048 * The caller must place the interned string into the stringtable
45049 * immediately (without chance of a longjmp); otherwise the string
45050 * is lost.
45051 */
45052
45053DUK_LOCAL
45054duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
45055 const duk_uint8_t *str,
45056 duk_uint32_t blen,
45057 duk_uint32_t strhash,
45058 const duk_uint8_t *extdata) {
45059 duk_hstring *res = NULL;
45060 duk_uint8_t *data;
45061 duk_size_t alloc_size;
45062 duk_uarridx_t dummy;
45063 duk_uint32_t clen;
45064
45065#if defined(DUK_USE_STRLEN16)
45066 /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */
45067 if (blen > 0xffffUL) {
45068 DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern"));
45069 return NULL;
45070 }
45071#endif
45072
45073 if (extdata) {
45074 alloc_size = (duk_size_t) sizeof(duk_hstring_external);
45075 res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
45076 if (!res) {
45077 goto alloc_error;
45078 }
45079 DUK_MEMZERO(res, sizeof(duk_hstring_external));
45080#if defined(DUK_USE_EXPLICIT_NULL_INIT)
45081 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
45082#endif
45083 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA);
45084
45085 ((duk_hstring_external *) res)->extdata = extdata;
45086 } else {
45087 /* NUL terminate for convenient C access */
45088 alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1);
45089 res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
45090 if (!res) {
45091 goto alloc_error;
45092 }
45093 DUK_MEMZERO(res, sizeof(duk_hstring));
45094#if defined(DUK_USE_EXPLICIT_NULL_INIT)
45095 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
45096#endif
45097 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
45098
45099 data = (duk_uint8_t *) (res + 1);
45100 DUK_MEMCPY(data, str, blen);
45101 data[blen] = (duk_uint8_t) 0;
45102 }
45103
45104 DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res));
45105 if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) {
45106 DUK_HSTRING_SET_ARRIDX(res);
45107 }
45108
45109 /* All strings beginning with 0xff are treated as "internal",
45110 * even strings interned by the user. This allows user code to
45111 * create internal properties too, and makes behavior consistent
45112 * in case user code happens to use a string also used by Duktape
45113 * (such as string has already been interned and has the 'internal'
45114 * flag set).
45115 */
45116 DUK_ASSERT(!DUK_HSTRING_HAS_INTERNAL(res));
45117 if (blen > 0 && str[0] == (duk_uint8_t) 0xff) {
45118 DUK_HSTRING_SET_INTERNAL(res);
45119 }
45120
45121 DUK_HSTRING_SET_HASH(res, strhash);
45122 DUK_HSTRING_SET_BYTELEN(res, blen);
45123
45124 clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen);
45125 DUK_ASSERT(clen <= blen);
45126#if defined(DUK_USE_HSTRING_CLEN)
45127 DUK_HSTRING_SET_CHARLEN(res, clen);
45128#endif
45129
45130 /* Using an explicit 'ASCII' flag has larger footprint (one call site
45131 * only) but is quite useful for the case when there's no explicit
45132 * 'clen' in duk_hstring.
45133 */
45134 DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
45135 if (clen == blen) {
45136 DUK_HSTRING_SET_ASCII(res);
45137 }
45138
45139 DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld",
45140 (unsigned long) DUK_HSTRING_GET_HASH(res),
45141 (long) DUK_HSTRING_GET_BYTELEN(res),
45142 (long) DUK_HSTRING_GET_CHARLEN(res),
45143 (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0),
45144 (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0)));
45145
45146 return res;
45147
45148 alloc_error:
45149 DUK_FREE(heap, res);
45150 return NULL;
45151}
45152
45153/*
45154 * String table algorithm: fixed size string table with array chaining
45155 *
45156 * The top level string table has a fixed size, with each slot holding
45157 * either NULL, string pointer, or pointer to a separately allocated
45158 * string pointer list.
45159 *
45160 * This is good for low memory environments using a pool allocator: the
45161 * top level allocation has a fixed size and the pointer lists have quite
45162 * small allocation size, which further matches the typical pool sizes
45163 * needed by objects, strings, property tables, etc.
45164 */
45165
45166#if defined(DUK_USE_STRTAB_CHAIN)
45167
45168#if defined(DUK_USE_HEAPPTR16)
45169DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
45170 duk_small_uint_t slotidx;
45171 duk_strtab_entry *e;
45172 duk_uint16_t *lst;
45173 duk_uint16_t *new_lst;
45174 duk_size_t i, n;
45175 duk_uint16_t null16 = heap->heapptr_null16;
45176 duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45177
45178 DUK_ASSERT(heap != NULL);
45179 DUK_ASSERT(h != NULL);
45180
45181 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45182 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45183
45184 e = heap->strtable + slotidx;
45185 if (e->listlen == 0) {
45186 if (e->u.str16 == null16) {
45187 e->u.str16 = h16;
45188 } else {
45189 /* Now two entries in the same slot, alloc list */
45190 lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2);
45191 if (lst == NULL) {
45192 return 1; /* fail */
45193 }
45194 lst[0] = e->u.str16;
45195 lst[1] = h16;
45196 e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst);
45197 e->listlen = 2;
45198 }
45199 } else {
45200 DUK_ASSERT(e->u.strlist16 != null16);
45201 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45202 DUK_ASSERT(lst != NULL);
45203 for (i = 0, n = e->listlen; i < n; i++) {
45204 if (lst[i] == null16) {
45205 lst[i] = h16;
45206 return 0;
45207 }
45208 }
45209
45210 if (e->listlen + 1 == 0) {
45211 /* Overflow, relevant mainly when listlen is 16 bits. */
45212 return 1; /* fail */
45213 }
45214
45215 new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1));
45216 if (new_lst == NULL) {
45217 return 1; /* fail */
45218 }
45219 new_lst[e->listlen++] = h16;
45220 e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst);
45221 }
45222 return 0;
45223}
45224#else /* DUK_USE_HEAPPTR16 */
45225DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
45226 duk_small_uint_t slotidx;
45227 duk_strtab_entry *e;
45228 duk_hstring **lst;
45229 duk_hstring **new_lst;
45230 duk_size_t i, n;
45231
45232 DUK_ASSERT(heap != NULL);
45233 DUK_ASSERT(h != NULL);
45234
45235 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45236 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45237
45238 e = heap->strtable + slotidx;
45239 if (e->listlen == 0) {
45240 if (e->u.str == NULL) {
45241 e->u.str = h;
45242 } else {
45243 /* Now two entries in the same slot, alloc list */
45244 lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2);
45245 if (lst == NULL) {
45246 return 1; /* fail */
45247 }
45248 lst[0] = e->u.str;
45249 lst[1] = h;
45250 e->u.strlist = lst;
45251 e->listlen = 2;
45252 }
45253 } else {
45254 DUK_ASSERT(e->u.strlist != NULL);
45255 lst = e->u.strlist;
45256 for (i = 0, n = e->listlen; i < n; i++) {
45257 if (lst[i] == NULL) {
45258 lst[i] = h;
45259 return 0;
45260 }
45261 }
45262
45263 if (e->listlen + 1 == 0) {
45264 /* Overflow, relevant mainly when listlen is 16 bits. */
45265 return 1; /* fail */
45266 }
45267
45268 new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1));
45269 if (new_lst == NULL) {
45270 return 1; /* fail */
45271 }
45272 new_lst[e->listlen++] = h;
45273 e->u.strlist = new_lst;
45274 }
45275 return 0;
45276}
45277#endif /* DUK_USE_HEAPPTR16 */
45278
45279#if defined(DUK_USE_HEAPPTR16)
45280DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
45281 duk_small_uint_t slotidx;
45282 duk_strtab_entry *e;
45283 duk_uint16_t *lst;
45284 duk_size_t i, n;
45285 duk_uint16_t null16 = heap->heapptr_null16;
45286
45287 DUK_ASSERT(heap != NULL);
45288
45289 slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
45290 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45291
45292 e = heap->strtable + slotidx;
45293 if (e->listlen == 0) {
45294 if (e->u.str16 != null16) {
45295 duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
45296 DUK_ASSERT(h != NULL);
45297 if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
45298 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
45299 return h;
45300 }
45301 }
45302 } else {
45303 DUK_ASSERT(e->u.strlist16 != null16);
45304 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45305 DUK_ASSERT(lst != NULL);
45306 for (i = 0, n = e->listlen; i < n; i++) {
45307 if (lst[i] != null16) {
45308 duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]);
45309 DUK_ASSERT(h != NULL);
45310 if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
45311 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
45312 return h;
45313 }
45314 }
45315 }
45316 }
45317
45318 return NULL;
45319}
45320#else /* DUK_USE_HEAPPTR16 */
45321DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
45322 duk_small_uint_t slotidx;
45323 duk_strtab_entry *e;
45324 duk_hstring **lst;
45325 duk_size_t i, n;
45326
45327 DUK_ASSERT(heap != NULL);
45328
45329 slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
45330 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45331
45332 e = heap->strtable + slotidx;
45333 if (e->listlen == 0) {
45334 if (e->u.str != NULL &&
45335 DUK_HSTRING_GET_BYTELEN(e->u.str) == blen &&
45336 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) {
45337 return e->u.str;
45338 }
45339 } else {
45340 DUK_ASSERT(e->u.strlist != NULL);
45341 lst = e->u.strlist;
45342 for (i = 0, n = e->listlen; i < n; i++) {
45343 if (lst[i] != NULL &&
45344 DUK_HSTRING_GET_BYTELEN(lst[i]) == blen &&
45345 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) {
45346 return lst[i];
45347 }
45348 }
45349 }
45350
45351 return NULL;
45352}
45353#endif /* DUK_USE_HEAPPTR16 */
45354
45355#if defined(DUK_USE_HEAPPTR16)
45356DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
45357 duk_small_uint_t slotidx;
45358 duk_strtab_entry *e;
45359 duk_uint16_t *lst;
45360 duk_size_t i, n;
45361 duk_uint16_t h16;
45362 duk_uint16_t null16 = heap->heapptr_null16;
45363
45364 DUK_ASSERT(heap != NULL);
45365 DUK_ASSERT(h != NULL);
45366
45367 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45368 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45369
45370 DUK_ASSERT(h != NULL);
45371 h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45372
45373 e = heap->strtable + slotidx;
45374 if (e->listlen == 0) {
45375 if (e->u.str16 == h16) {
45376 e->u.str16 = null16;
45377 return;
45378 }
45379 } else {
45380 DUK_ASSERT(e->u.strlist16 != null16);
45381 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45382 DUK_ASSERT(lst != NULL);
45383 for (i = 0, n = e->listlen; i < n; i++) {
45384 if (lst[i] == h16) {
45385 lst[i] = null16;
45386 return;
45387 }
45388 }
45389 }
45390
45391 DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
45392 DUK_UNREACHABLE();
45393 return;
45394}
45395#else /* DUK_USE_HEAPPTR16 */
45396DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
45397 duk_small_uint_t slotidx;
45398 duk_strtab_entry *e;
45399 duk_hstring **lst;
45400 duk_size_t i, n;
45401
45402 DUK_ASSERT(heap != NULL);
45403 DUK_ASSERT(h != NULL);
45404
45405 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45406 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45407
45408 e = heap->strtable + slotidx;
45409 if (e->listlen == 0) {
45410 DUK_ASSERT(h != NULL);
45411 if (e->u.str == h) {
45412 e->u.str = NULL;
45413 return;
45414 }
45415 } else {
45416 DUK_ASSERT(e->u.strlist != NULL);
45417 lst = e->u.strlist;
45418 for (i = 0, n = e->listlen; i < n; i++) {
45419 DUK_ASSERT(h != NULL);
45420 if (lst[i] == h) {
45421 lst[i] = NULL;
45422 return;
45423 }
45424 }
45425 }
45426
45427 DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
45428 DUK_UNREACHABLE();
45429 return;
45430}
45431#endif /* DUK_USE_HEAPPTR16 */
45432
45433#if defined(DUK_USE_DEBUG)
45434DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
45435 duk_strtab_entry *e;
45436 duk_small_uint_t i;
45437 duk_size_t j, n, used;
45438#if defined(DUK_USE_HEAPPTR16)
45439 duk_uint16_t *lst;
45440 duk_uint16_t null16 = heap->heapptr_null16;
45441#else
45442 duk_hstring **lst;
45443#endif
45444
45445 DUK_ASSERT(heap != NULL);
45446
45447 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
45448 e = heap->strtable + i;
45449
45450 if (e->listlen == 0) {
45451#if defined(DUK_USE_HEAPPTR16)
45452 DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0)));
45453#else
45454 DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0)));
45455#endif
45456 } else {
45457 used = 0;
45458#if defined(DUK_USE_HEAPPTR16)
45459 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45460#else
45461 lst = e->u.strlist;
45462#endif
45463 DUK_ASSERT(lst != NULL);
45464 for (j = 0, n = e->listlen; j < n; j++) {
45465#if defined(DUK_USE_HEAPPTR16)
45466 if (lst[j] != null16) {
45467#else
45468 if (lst[j] != NULL) {
45469#endif
45470 used++;
45471 }
45472 }
45473 DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen));
45474 }
45475 }
45476}
45477#endif /* DUK_USE_DEBUG */
45478
45479#endif /* DUK_USE_STRTAB_CHAIN */
45480
45481/*
45482 * String table algorithm: closed hashing with a probe sequence
45483 *
45484 * This is the default algorithm and works fine for environments with
45485 * minimal memory constraints.
45486 */
45487
45488#if defined(DUK_USE_STRTAB_PROBE)
45489
45490/* Count actually used (non-NULL, non-DELETED) entries. */
45491DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) {
45492 duk_int_t res = 0;
45493 duk_uint_fast32_t i, n;
45494#if defined(DUK_USE_HEAPPTR16)
45495 duk_uint16_t null16 = heap->heapptr_null16;
45496 duk_uint16_t deleted16 = heap->heapptr_deleted16;
45497#endif
45498
45499 n = (duk_uint_fast32_t) heap->st_size;
45500 for (i = 0; i < n; i++) {
45501#if defined(DUK_USE_HEAPPTR16)
45502 if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) {
45503#else
45504 if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) {
45505#endif
45506 res++;
45507 }
45508 }
45509 return res;
45510}
45511
45512#if defined(DUK_USE_HEAPPTR16)
45513DUK_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) {
45514#else
45515DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
45516#endif
45517 duk_uint32_t i;
45518 duk_uint32_t step;
45519#if defined(DUK_USE_HEAPPTR16)
45520 duk_uint16_t null16 = heap->heapptr_null16;
45521 duk_uint16_t deleted16 = heap->heapptr_deleted16;
45522#endif
45523
45524 DUK_ASSERT(size > 0);
45525
45526 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size);
45527 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h));
45528 for (;;) {
45529#if defined(DUK_USE_HEAPPTR16)
45530 duk_uint16_t e16 = entries16[i];
45531#else
45532 duk_hstring *e = entries[i];
45533#endif
45534
45535#if defined(DUK_USE_HEAPPTR16)
45536 /* XXX: could check for e16 == 0 because NULL is guaranteed to
45537 * encode to zero.
45538 */
45539 if (e16 == null16) {
45540#else
45541 if (e == NULL) {
45542#endif
45543 DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i));
45544#if defined(DUK_USE_HEAPPTR16)
45545 entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45546#else
45547 entries[i] = h;
45548#endif
45549 (*p_used)++;
45550 break;
45551#if defined(DUK_USE_HEAPPTR16)
45552 } else if (e16 == deleted16) {
45553#else
45554 } else if (e == DUK__DELETED_MARKER(heap)) {
45555#endif
45556 /* st_used remains the same, DELETED is counted as used */
45557 DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i));
45558#if defined(DUK_USE_HEAPPTR16)
45559 entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45560#else
45561 entries[i] = h;
45562#endif
45563 break;
45564 }
45565 DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i));
45566 i = (i + step) % size;
45567
45568 /* looping should never happen */
45569 DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size));
45570 }
45571}
45572
45573#if defined(DUK_USE_HEAPPTR16)
45574DUK_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) {
45575#else
45576DUK_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) {
45577#endif
45578 duk_uint32_t i;
45579 duk_uint32_t step;
45580
45581 DUK_ASSERT(size > 0);
45582
45583 i = DUK__HASH_INITIAL(strhash, size);
45584 step = DUK__HASH_PROBE_STEP(strhash);
45585 for (;;) {
45586 duk_hstring *e;
45587#if defined(DUK_USE_HEAPPTR16)
45588 e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]);
45589#else
45590 e = entries[i];
45591#endif
45592
45593 if (!e) {
45594 return NULL;
45595 }
45596 if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) {
45597 if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) {
45598 DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)",
45599 (long) i, (long) step, (long) size));
45600 return e;
45601 }
45602 }
45603 DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)",
45604 (long) i, (long) step, (long) size));
45605 i = (i + step) % size;
45606
45607 /* looping should never happen */
45608 DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size));
45609 }
45610 DUK_UNREACHABLE();
45611}
45612
45613#if defined(DUK_USE_HEAPPTR16)
45614DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) {
45615#else
45616DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) {
45617#endif
45618 duk_uint32_t i;
45619 duk_uint32_t step;
45620 duk_uint32_t hash;
45621#if defined(DUK_USE_HEAPPTR16)
45622 duk_uint16_t null16 = heap->heapptr_null16;
45623 duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45624#endif
45625
45626 DUK_ASSERT(size > 0);
45627
45628 hash = DUK_HSTRING_GET_HASH(h);
45629 i = DUK__HASH_INITIAL(hash, size);
45630 step = DUK__HASH_PROBE_STEP(hash);
45631 for (;;) {
45632#if defined(DUK_USE_HEAPPTR16)
45633 duk_uint16_t e16 = entries16[i];
45634#else
45635 duk_hstring *e = entries[i];
45636#endif
45637
45638#if defined(DUK_USE_HEAPPTR16)
45639 if (e16 == null16) {
45640#else
45641 if (!e) {
45642#endif
45643 DUK_UNREACHABLE();
45644 break;
45645 }
45646#if defined(DUK_USE_HEAPPTR16)
45647 if (e16 == h16) {
45648#else
45649 if (e == h) {
45650#endif
45651 /* st_used remains the same, DELETED is counted as used */
45652 DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i));
45653#if defined(DUK_USE_HEAPPTR16)
45654 entries16[i] = heap->heapptr_deleted16;
45655#else
45656 entries[i] = DUK__DELETED_MARKER(heap);
45657#endif
45658 break;
45659 }
45660
45661 DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i));
45662 i = (i + step) % size;
45663
45664 /* looping should never happen */
45665 DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size));
45666 }
45667}
45668
45669DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) {
45670#if defined(DUK_USE_DEBUG)
45671 duk_uint32_t old_used = heap->st_used;
45672#endif
45673 duk_uint32_t old_size = heap->st_size;
45674#if defined(DUK_USE_HEAPPTR16)
45675 duk_uint16_t *old_entries = heap->strtable16;
45676 duk_uint16_t *new_entries = NULL;
45677#else
45678 duk_hstring **old_entries = heap->strtable;
45679 duk_hstring **new_entries = NULL;
45680#endif
45681 duk_uint32_t new_used = 0;
45682 duk_uint32_t i;
45683
45684#if defined(DUK_USE_DEBUG)
45685 DUK_UNREF(old_used); /* unused with some debug level combinations */
45686#endif
45687
45688#ifdef DUK_USE_DDDPRINT
45689 DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
45690 (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
45691 (long) (((double) old_used) / ((double) old_size) * 100.0),
45692 (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap),
45693 (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0)));
45694#endif
45695
45696 DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */
45697 DUK_ASSERT(old_entries);
45698
45699 /*
45700 * The attempt to allocate may cause a GC. Such a GC must not attempt to resize
45701 * the stringtable (though it can be swept); finalizer execution and object
45702 * compaction must also be postponed to avoid the pressure to add strings to the
45703 * string table. Call site must prevent these.
45704 */
45705
45706#if defined(DUK_USE_MARK_AND_SWEEP)
45707 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE);
45708 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS);
45709 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION);
45710#endif
45711
45712#if defined(DUK_USE_HEAPPTR16)
45713 new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size);
45714#else
45715 new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);
45716#endif
45717
45718 if (!new_entries) {
45719 goto resize_error;
45720 }
45721
45722#if defined(DUK_USE_EXPLICIT_NULL_INIT)
45723 for (i = 0; i < new_size; i++) {
45724#if defined(DUK_USE_HEAPPTR16)
45725 new_entries[i] = heap->heapptr_null16;
45726#else
45727 new_entries[i] = NULL;
45728#endif
45729 }
45730#else
45731#if defined(DUK_USE_HEAPPTR16)
45732 /* Relies on NULL encoding to zero. */
45733 DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size);
45734#else
45735 DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
45736#endif
45737#endif
45738
45739 /* Because new_size > duk__count_used_probe(heap), guaranteed to work */
45740 for (i = 0; i < old_size; i++) {
45741 duk_hstring *e;
45742
45743#if defined(DUK_USE_HEAPPTR16)
45744 e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]);
45745#else
45746 e = old_entries[i];
45747#endif
45748 if (e == NULL || e == DUK__DELETED_MARKER(heap)) {
45749 continue;
45750 }
45751 /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */
45752 duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e);
45753 }
45754
45755#ifdef DUK_USE_DDPRINT
45756 DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
45757 (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
45758 (long) (((double) old_used) / ((double) old_size) * 100.0),
45759 (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used,
45760 (long) (((double) new_used) / ((double) new_size) * 100.0)));
45761#endif
45762
45763#if defined(DUK_USE_HEAPPTR16)
45764 DUK_FREE(heap, heap->strtable16);
45765 heap->strtable16 = new_entries;
45766#else
45767 DUK_FREE(heap, heap->strtable);
45768 heap->strtable = new_entries;
45769#endif
45770 heap->st_size = new_size;
45771 heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */
45772
45773 return 0; /* OK */
45774
45775 resize_error:
45776 DUK_FREE(heap, new_entries);
45777 return 1; /* FAIL */
45778}
45779
45780DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) {
45781 duk_uint32_t new_size;
45782 duk_bool_t ret;
45783
45784 new_size = (duk_uint32_t) duk__count_used_probe(heap);
45785 if (new_size >= 0x80000000UL) {
45786 new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
45787 } else {
45788 new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
45789 new_size = duk_util_get_hash_prime(new_size);
45790 }
45791 DUK_ASSERT(new_size > 0);
45792
45793 /* rehash even if old and new sizes are the same to get rid of
45794 * DELETED entries.
45795 */
45796
45797 ret = duk__resize_strtab_raw_probe(heap, new_size);
45798
45799 return ret;
45800}
45801
45802DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) {
45803 duk_uint32_t new_free;
45804 duk_uint32_t tmp1;
45805 duk_uint32_t tmp2;
45806
45807 DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */
45808 new_free = heap->st_size - new_used; /* unsigned intentionally */
45809
45810 /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */
45811 /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */
45812
45813 tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR;
45814 tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR;
45815
45816 if (new_free <= tmp1 || new_used <= tmp2) {
45817 /* load factor too low or high, count actually used entries and resize */
45818 return duk__resize_strtab_probe(heap);
45819 } else {
45820 return 0; /* OK */
45821 }
45822}
45823
45824#if defined(DUK_USE_DEBUG)
45825DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
45826 duk_uint32_t i;
45827 duk_hstring *h;
45828
45829 DUK_ASSERT(heap != NULL);
45830#if defined(DUK_USE_HEAPPTR16)
45831 DUK_ASSERT(heap->strtable16 != NULL);
45832#else
45833 DUK_ASSERT(heap->strtable != NULL);
45834#endif
45835 DUK_UNREF(h);
45836
45837 for (i = 0; i < heap->st_size; i++) {
45838#if defined(DUK_USE_HEAPPTR16)
45839 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
45840#else
45841 h = heap->strtable[i];
45842#endif
45843
45844 DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h));
45845 }
45846}
45847#endif /* DUK_USE_DEBUG */
45848
45849#endif /* DUK_USE_STRTAB_PROBE */
45850
45851/*
45852 * Raw intern and lookup
45853 */
45854
45855DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
45856 duk_hstring *res;
45857 const duk_uint8_t *extdata;
45858#if defined(DUK_USE_MARK_AND_SWEEP)
45859 duk_small_uint_t prev_mark_and_sweep_base_flags;
45860#endif
45861
45862 /* Prevent any side effects on the string table and the caller provided
45863 * str/blen arguments while interning is in progress. For example, if
45864 * the caller provided str/blen from a dynamic buffer, a finalizer might
45865 * resize that dynamic buffer, invalidating the call arguments.
45866 */
45867#if defined(DUK_USE_MARK_AND_SWEEP)
45868 DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
45869 prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
45870 DUK__PREVENT_MS_SIDE_EFFECTS(heap);
45871#endif
45872
45873#if defined(DUK_USE_STRTAB_PROBE)
45874 if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) {
45875 goto failed;
45876 }
45877#endif
45878
45879 /* For manual testing only. */
45880#if 0
45881 {
45882 duk_size_t i;
45883 DUK_PRINTF("INTERN: \"");
45884 for (i = 0; i < blen; i++) {
45885 duk_uint8_t x = str[i];
45886 if (x >= 0x20 && x <= 0x7e && x != '"' && x != '\\') {
45887 DUK_PRINTF("%c", (int) x); /* char: use int cast */
45888 } else {
45889 DUK_PRINTF("\\x%02lx", (long) x);
45890 }
45891 }
45892 DUK_PRINTF("\"\n");
45893 }
45894#endif
45895
45896#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
45897 extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
45898#else
45899 extdata = (const duk_uint8_t *) NULL;
45900#endif
45901 res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata);
45902 if (!res) {
45903 goto failed;
45904 }
45905
45906#if defined(DUK_USE_STRTAB_CHAIN)
45907 if (duk__insert_hstring_chain(heap, res)) {
45908 /* failed */
45909 DUK_FREE(heap, res);
45910 goto failed;
45911 }
45912#elif defined(DUK_USE_STRTAB_PROBE)
45913 /* guaranteed to succeed */
45914 duk__insert_hstring_probe(heap,
45915#if defined(DUK_USE_HEAPPTR16)
45916 heap->strtable16,
45917#else
45918 heap->strtable,
45919#endif
45920 heap->st_size,
45921 &heap->st_used,
45922 res);
45923#else
45924#error internal error, invalid strtab options
45925#endif
45926
45927 /* Note: hstring is in heap but has refcount zero and is not strongly reachable.
45928 * Caller should increase refcount and make the hstring reachable before any
45929 * operations which require allocation (and possible gc).
45930 */
45931
45932 done:
45933#if defined(DUK_USE_MARK_AND_SWEEP)
45934 heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
45935#endif
45936 return res;
45937
45938 failed:
45939 res = NULL;
45940 goto done;
45941}
45942
45943DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) {
45944 duk_hstring *res;
45945
45946 DUK_ASSERT(out_strhash);
45947
45948 *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
45949
45950#if defined(DUK_USE_ROM_STRINGS)
45951 {
45952 duk_small_uint_t i;
45953 /* XXX: This is VERY inefficient now, and should be e.g. a
45954 * binary search or perfect hash, to be fixed.
45955 */
45956 for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) {
45957 duk_hstring *romstr;
45958 romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]);
45959 if (blen == DUK_HSTRING_GET_BYTELEN(romstr) &&
45960 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) {
45961 DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
45962 romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr)));
45963 DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr));
45964 *out_strhash = DUK_HSTRING_GET_HASH(romstr);
45965 return romstr;
45966 }
45967 }
45968 }
45969#endif /* DUK_USE_ROM_STRINGS */
45970
45971#if defined(DUK_USE_STRTAB_CHAIN)
45972 res = duk__find_matching_string_chain(heap, str, blen, *out_strhash);
45973#elif defined(DUK_USE_STRTAB_PROBE)
45974 res = duk__find_matching_string_probe(heap,
45975#if defined(DUK_USE_HEAPPTR16)
45976 heap->strtable16,
45977#else
45978 heap->strtable,
45979#endif
45980 heap->st_size,
45981 str,
45982 blen,
45983 *out_strhash);
45984#else
45985#error internal error, invalid strtab options
45986#endif
45987
45988 return res;
45989}
45990
45991/*
45992 * Exposed calls
45993 */
45994
45995#if 0 /*unused*/
45996DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
45997 duk_uint32_t strhash; /* dummy */
45998 return duk__do_lookup(heap, str, blen, &strhash);
45999}
46000#endif
46001
46002DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
46003 duk_hstring *res;
46004 duk_uint32_t strhash;
46005
46006 /* caller is responsible for ensuring this */
46007 DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN);
46008
46009 res = duk__do_lookup(heap, str, blen, &strhash);
46010 if (res) {
46011 return res;
46012 }
46013
46014 res = duk__do_intern(heap, str, blen, strhash);
46015 return res; /* may be NULL */
46016}
46017
46018DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
46019 duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen);
46020 if (!res) {
46021 DUK_ERROR_ALLOC_DEFMSG(thr);
46022 }
46023 return res;
46024}
46025
46026#if 0 /*unused*/
46027DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) {
46028 char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
46029 DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
46030 buf[sizeof(buf) - 1] = (char) 0;
46031 DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
46032 return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
46033}
46034#endif
46035
46036DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) {
46037 char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
46038 DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
46039 buf[sizeof(buf) - 1] = (char) 0;
46040 DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
46041 return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
46042}
46043
46044DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
46045 duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val);
46046 if (!res) {
46047 DUK_ERROR_ALLOC_DEFMSG(thr);
46048 }
46049 return res;
46050}
46051
46052/* find and remove string from stringtable; caller must free the string itself */
46053#if defined(DUK_USE_REFERENCE_COUNTING)
46054DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) {
46055 DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h));
46056
46057#if defined(DUK_USE_STRTAB_CHAIN)
46058 duk__remove_matching_hstring_chain(heap, h);
46059#elif defined(DUK_USE_STRTAB_PROBE)
46060 duk__remove_matching_hstring_probe(heap,
46061#if defined(DUK_USE_HEAPPTR16)
46062 heap->strtable16,
46063#else
46064 heap->strtable,
46065#endif
46066 heap->st_size,
46067 h);
46068#else
46069#error internal error, invalid strtab options
46070#endif
46071}
46072#endif
46073
46074#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
46075DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) {
46076 duk_small_uint_t prev_mark_and_sweep_base_flags;
46077 /* Force a resize so that DELETED entries are eliminated.
46078 * Another option would be duk__recheck_strtab_size_probe();
46079 * but since that happens on every intern anyway, this whole
46080 * check can now be disabled.
46081 */
46082
46083 DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
46084 prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
46085 DUK__PREVENT_MS_SIDE_EFFECTS(heap);
46086
46087#if defined(DUK_USE_STRTAB_CHAIN)
46088 DUK_UNREF(heap);
46089#elif defined(DUK_USE_STRTAB_PROBE)
46090 (void) duk__resize_strtab_probe(heap);
46091#endif
46092
46093 heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
46094}
46095#endif
46096
46097#if defined(DUK_USE_STRTAB_CHAIN)
46098DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
46099 /* Free strings in the stringtable and any allocations needed
46100 * by the stringtable itself.
46101 */
46102 duk_uint_fast32_t i, j;
46103 duk_strtab_entry *e;
46104#if defined(DUK_USE_HEAPPTR16)
46105 duk_uint16_t *lst;
46106 duk_uint16_t null16 = heap->heapptr_null16;
46107#else
46108 duk_hstring **lst;
46109#endif
46110 duk_hstring *h;
46111
46112 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
46113 e = heap->strtable + i;
46114 if (e->listlen > 0) {
46115#if defined(DUK_USE_HEAPPTR16)
46116 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
46117#else
46118 lst = e->u.strlist;
46119#endif
46120 DUK_ASSERT(lst != NULL);
46121
46122 for (j = 0; j < e->listlen; j++) {
46123#if defined(DUK_USE_HEAPPTR16)
46124 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
46125 lst[j] = null16;
46126#else
46127 h = lst[j];
46128 lst[j] = NULL;
46129#endif
46130 /* strings may have inner refs (extdata) in some cases */
46131 if (h != NULL) {
46132 duk_free_hstring_inner(heap, h);
46133 DUK_FREE(heap, h);
46134 }
46135 }
46136#if defined(DUK_USE_HEAPPTR16)
46137 e->u.strlist16 = null16;
46138#else
46139 e->u.strlist = NULL;
46140#endif
46141 DUK_FREE(heap, lst);
46142 } else {
46143#if defined(DUK_USE_HEAPPTR16)
46144 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
46145 e->u.str16 = null16;
46146#else
46147 h = e->u.str;
46148 e->u.str = NULL;
46149#endif
46150 if (h != NULL) {
46151 duk_free_hstring_inner(heap, h);
46152 DUK_FREE(heap, h);
46153 }
46154 }
46155 e->listlen = 0;
46156 }
46157}
46158#endif /* DUK_USE_STRTAB_CHAIN */
46159
46160#if defined(DUK_USE_STRTAB_PROBE)
46161DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
46162 duk_uint_fast32_t i;
46163 duk_hstring *h;
46164
46165#if defined(DUK_USE_HEAPPTR16)
46166 if (heap->strtable16) {
46167#else
46168 if (heap->strtable) {
46169#endif
46170 for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
46171#if defined(DUK_USE_HEAPPTR16)
46172 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
46173#else
46174 h = heap->strtable[i];
46175#endif
46176 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
46177 continue;
46178 }
46179 DUK_ASSERT(h != NULL);
46180
46181 /* strings may have inner refs (extdata) in some cases */
46182 duk_free_hstring_inner(heap, h);
46183 DUK_FREE(heap, h);
46184#if 0 /* not strictly necessary */
46185 heap->strtable[i] = NULL;
46186#endif
46187 }
46188#if defined(DUK_USE_HEAPPTR16)
46189 DUK_FREE(heap, heap->strtable16);
46190#else
46191 DUK_FREE(heap, heap->strtable);
46192#endif
46193#if 0 /* not strictly necessary */
46194 heap->strtable = NULL;
46195#endif
46196 }
46197}
46198#endif /* DUK_USE_STRTAB_PROBE */
46199
46200/* Undefine local defines */
46201#undef DUK__HASH_INITIAL
46202#undef DUK__HASH_PROBE_STEP
46203#undef DUK__DELETED_MARKER
46204#line 1 "duk_hobject_alloc.c"
46205/*
46206 * Hobject allocation.
46207 *
46208 * Provides primitive allocation functions for all object types (plain object,
46209 * compiled function, native function, thread). The object return is not yet
46210 * in "heap allocated" list and has a refcount of zero, so caller must careful.
46211 */
46212
46213/* include removed: duk_internal.h */
46214
46215DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) {
46216#ifdef DUK_USE_EXPLICIT_NULL_INIT
46217 DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
46218#endif
46219
46220 /* XXX: macro? sets both heaphdr and object flags */
46221 obj->hdr.h_flags = hobject_flags;
46222 DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */
46223
46224#if defined(DUK_USE_HEAPPTR16)
46225 /* Zero encoded pointer is required to match NULL */
46226 DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
46227#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
46228 DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
46229#endif
46230#endif
46231 DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr);
46232 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
46233
46234 /*
46235 * obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
46236 * with this properly. This is intentional: empty objects consume a minimum
46237 * amount of memory. Further, an initial allocation might fail and cause
46238 * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
46239 */
46240}
46241
46242/*
46243 * Allocate an duk_hobject.
46244 *
46245 * The allocated object has no allocation for properties; the caller may
46246 * want to force a resize if a desired size is known.
46247 *
46248 * The allocated object has zero reference count and is not reachable.
46249 * The caller MUST make the object reachable and increase its reference
46250 * count before invoking any operation that might require memory allocation.
46251 */
46252
46253DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46254 duk_hobject *res;
46255
46256 DUK_ASSERT(heap != NULL);
46257
46258 /* different memory layout, alloc size, and init */
46259 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPILEDFUNCTION) == 0);
46260 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATIVEFUNCTION) == 0);
46261 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);
46262
46263 res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
46264 if (!res) {
46265 return NULL;
46266 }
46267 DUK_MEMZERO(res, sizeof(duk_hobject));
46268
46269 duk__init_object_parts(heap, res, hobject_flags);
46270
46271 return res;
46272}
46273
46274DUK_INTERNAL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46275 duk_hcompiledfunction *res;
46276
46277 res = (duk_hcompiledfunction *) DUK_ALLOC(heap, sizeof(duk_hcompiledfunction));
46278 if (!res) {
46279 return NULL;
46280 }
46281 DUK_MEMZERO(res, sizeof(duk_hcompiledfunction));
46282
46283 duk__init_object_parts(heap, &res->obj, hobject_flags);
46284
46285#ifdef DUK_USE_EXPLICIT_NULL_INIT
46286#ifdef DUK_USE_HEAPPTR16
46287 /* NULL pointer is required to encode to zero, so memset is enough. */
46288#else
46289 res->data = NULL;
46290 res->funcs = NULL;
46291 res->bytecode = NULL;
46292#endif
46293#endif
46294
46295 return res;
46296}
46297
46298DUK_INTERNAL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46299 duk_hnativefunction *res;
46300
46301 res = (duk_hnativefunction *) DUK_ALLOC(heap, sizeof(duk_hnativefunction));
46302 if (!res) {
46303 return NULL;
46304 }
46305 DUK_MEMZERO(res, sizeof(duk_hnativefunction));
46306
46307 duk__init_object_parts(heap, &res->obj, hobject_flags);
46308
46309#ifdef DUK_USE_EXPLICIT_NULL_INIT
46310 res->func = NULL;
46311#endif
46312
46313 return res;
46314}
46315
46316DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46317 duk_hbufferobject *res;
46318
46319 res = (duk_hbufferobject *) DUK_ALLOC(heap, sizeof(duk_hbufferobject));
46320 if (!res) {
46321 return NULL;
46322 }
46323 DUK_MEMZERO(res, sizeof(duk_hbufferobject));
46324
46325 duk__init_object_parts(heap, &res->obj, hobject_flags);
46326
46327#ifdef DUK_USE_EXPLICIT_NULL_INIT
46328 res->buf = NULL;
46329#endif
46330
46331 DUK_ASSERT_HBUFFEROBJECT_VALID(res);
46332 return res;
46333}
46334
46335/*
46336 * Allocate a new thread.
46337 *
46338 * Leaves the built-ins array uninitialized. The caller must either
46339 * initialize a new global context or share existing built-ins from
46340 * another thread.
46341 */
46342
46343DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46344 duk_hthread *res;
46345
46346 res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
46347 if (!res) {
46348 return NULL;
46349 }
46350 DUK_MEMZERO(res, sizeof(duk_hthread));
46351
46352 duk__init_object_parts(heap, &res->obj, hobject_flags);
46353
46354#ifdef DUK_USE_EXPLICIT_NULL_INIT
46355 res->ptr_curr_pc = NULL;
46356 res->heap = NULL;
46357 res->valstack = NULL;
46358 res->valstack_end = NULL;
46359 res->valstack_bottom = NULL;
46360 res->valstack_top = NULL;
46361 res->callstack = NULL;
46362 res->catchstack = NULL;
46363 res->resumer = NULL;
46364 res->compile_ctx = NULL,
46365#ifdef DUK_USE_HEAPPTR16
46366 res->strs16 = NULL;
46367#else
46368 res->strs = NULL;
46369#endif
46370 {
46371 int i;
46372 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
46373 res->builtins[i] = NULL;
46374 }
46375 }
46376#endif
46377 /* when nothing is running, API calls are in non-strict mode */
46378 DUK_ASSERT(res->strict == 0);
46379
46380 res->heap = heap;
46381 res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
46382 res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
46383 res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;
46384
46385 return res;
46386}
46387
46388#if 0 /* unused now */
46389DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) {
46390 duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags);
46391 if (!res) {
46392 DUK_ERROR_ALLOC_DEFMSG(thr);
46393 }
46394 return res;
46395}
46396#endif
46397#line 1 "duk_hobject_enum.c"
46398/*
46399 * Hobject enumeration support.
46400 *
46401 * Creates an internal enumeration state object to be used e.g. with for-in
46402 * enumeration. The state object contains a snapshot of target object keys
46403 * and internal control state for enumeration. Enumerator flags allow caller
46404 * to e.g. request internal/non-enumerable properties, and to enumerate only
46405 * "own" properties.
46406 *
46407 * Also creates the result value for e.g. Object.keys() based on the same
46408 * internal structure.
46409 *
46410 * This snapshot-based enumeration approach is used to simplify enumeration:
46411 * non-snapshot-based approaches are difficult to reconcile with mutating
46412 * the enumeration target, running multiple long-lived enumerators at the
46413 * same time, garbage collection details, etc. The downside is that the
46414 * enumerator object is memory inefficient especially for iterating arrays.
46415 */
46416
46417/* include removed: duk_internal.h */
46418
46419/* XXX: identify enumeration target with an object index (not top of stack) */
46420
46421/* must match exactly the number of internal properties inserted to enumerator */
46422#define DUK__ENUM_START_INDEX 2
46423
46424DUK_LOCAL const duk_uint16_t duk__bufferobject_virtual_props[] = {
46425 DUK_STRIDX_LENGTH,
46426 DUK_STRIDX_BYTE_LENGTH,
46427 DUK_STRIDX_BYTE_OFFSET,
46428 DUK_STRIDX_BYTES_PER_ELEMENT
46429};
46430
46431/*
46432 * Helper to sort array index keys. The keys are in the enumeration object
46433 * entry part, starting from DUK__ENUM_START_INDEX, and the entry part is dense.
46434 *
46435 * We use insertion sort because it is simple (leading to compact code,)
46436 * works nicely in-place, and minimizes operations if data is already sorted
46437 * or nearly sorted (which is a very common case here). It also minimizes
46438 * the use of element comparisons in general. This is nice because element
46439 * comparisons here involve re-parsing the string keys into numbers each
46440 * time, which is naturally very expensive.
46441 *
46442 * Note that the entry part values are all "true", e.g.
46443 *
46444 * "1" -> true, "3" -> true, "2" -> true
46445 *
46446 * so it suffices to only work in the key part without exchanging any keys,
46447 * simplifying the sort.
46448 *
46449 * http://en.wikipedia.org/wiki/Insertion_sort
46450 *
46451 * (Compiles to about 160 bytes now as a stand-alone function.)
46452 */
46453
46454DUK_LOCAL void duk__sort_array_indices(duk_hthread *thr, duk_hobject *h_obj) {
46455 duk_hstring **keys;
46456 duk_hstring **p_curr, **p_insert, **p_end;
46457 duk_hstring *h_curr;
46458 duk_uarridx_t val_highest, val_curr, val_insert;
46459
46460 DUK_ASSERT(h_obj != NULL);
46461 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h_obj) >= 2); /* control props */
46462 DUK_UNREF(thr);
46463
46464 if (DUK_HOBJECT_GET_ENEXT(h_obj) <= 1 + DUK__ENUM_START_INDEX) {
46465 return;
46466 }
46467
46468 keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
46469 p_end = keys + DUK_HOBJECT_GET_ENEXT(h_obj);
46470 keys += DUK__ENUM_START_INDEX;
46471
46472 DUK_DDD(DUK_DDDPRINT("keys=%p, p_end=%p (after skipping enum props)",
46473 (void *) keys, (void *) p_end));
46474
46475#ifdef DUK_USE_DDDPRINT
46476 {
46477 duk_uint_fast32_t i;
46478 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
46479 DUK_DDD(DUK_DDDPRINT("initial: %ld %p -> %!O",
46480 (long) i,
46481 (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
46482 (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
46483 }
46484 }
46485#endif
46486
46487 val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(keys[0]);
46488 for (p_curr = keys + 1; p_curr < p_end; p_curr++) {
46489 DUK_ASSERT(*p_curr != NULL);
46490 val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
46491
46492 if (val_curr >= val_highest) {
46493 DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
46494 "already in correct order, next",
46495 (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
46496 val_highest = val_curr;
46497 continue;
46498 }
46499
46500 DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
46501 "needs to be inserted",
46502 (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
46503
46504 /* Needs to be inserted; scan backwards, since we optimize
46505 * for the case where elements are nearly in order.
46506 */
46507
46508 p_insert = p_curr - 1;
46509 for (;;) {
46510 val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
46511 if (val_insert < val_curr) {
46512 DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> insert after this",
46513 (void *) p_insert, (long) val_insert, (long) val_curr));
46514 p_insert++;
46515 break;
46516 }
46517 if (p_insert == keys) {
46518 DUK_DDD(DUK_DDDPRINT("p_insert=%p -> out of keys, insert to beginning", (void *) p_insert));
46519 break;
46520 }
46521 DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> search backwards",
46522 (void *) p_insert, (long) val_insert, (long) val_curr));
46523 p_insert--;
46524 }
46525
46526 DUK_DDD(DUK_DDDPRINT("final p_insert=%p", (void *) p_insert));
46527
46528 /* .-- p_insert .-- p_curr
46529 * v v
46530 * | ... | insert | ... | curr
46531 */
46532
46533 h_curr = *p_curr;
46534 DUK_DDD(DUK_DDDPRINT("memmove: dest=%p, src=%p, size=%ld, h_curr=%p",
46535 (void *) (p_insert + 1), (void *) p_insert,
46536 (long) (p_curr - p_insert), (void *) h_curr));
46537
46538 DUK_MEMMOVE((void *) (p_insert + 1),
46539 (const void *) p_insert,
46540 (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
46541 *p_insert = h_curr;
46542 /* keep val_highest */
46543 }
46544
46545#ifdef DUK_USE_DDDPRINT
46546 {
46547 duk_uint_fast32_t i;
46548 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
46549 DUK_DDD(DUK_DDDPRINT("final: %ld %p -> %!O",
46550 (long) i,
46551 (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
46552 (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
46553 }
46554 }
46555#endif
46556}
46557
46558/*
46559 * Create an internal enumerator object E, which has its keys ordered
46560 * to match desired enumeration ordering. Also initialize internal control
46561 * properties for enumeration.
46562 *
46563 * Note: if an array was used to hold enumeration keys instead, an array
46564 * scan would be needed to eliminate duplicates found in the prototype chain.
46565 */
46566
46567DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags) {
46568 duk_hthread *thr = (duk_hthread *) ctx;
46569 duk_hobject *enum_target;
46570 duk_hobject *curr;
46571 duk_hobject *res;
46572#if defined(DUK_USE_ES6_PROXY)
46573 duk_hobject *h_proxy_target;
46574 duk_hobject *h_proxy_handler;
46575 duk_hobject *h_trap_result;
46576#endif
46577 duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
46578
46579 DUK_ASSERT(ctx != NULL);
46580
46581 DUK_DDD(DUK_DDDPRINT("create enumerator, stack top: %ld", (long) duk_get_top(ctx)));
46582
46583 enum_target = duk_require_hobject(ctx, -1);
46584 DUK_ASSERT(enum_target != NULL);
46585
46586 duk_push_object_internal(ctx);
46587 res = duk_require_hobject(ctx, -1);
46588
46589 DUK_DDD(DUK_DDDPRINT("created internal object"));
46590
46591 /* [enum_target res] */
46592
46593 /* Target must be stored so that we can recheck whether or not
46594 * keys still exist when we enumerate. This is not done if the
46595 * enumeration result comes from a proxy trap as there is no
46596 * real object to check against.
46597 */
46598 duk_push_hobject(ctx, enum_target);
46599 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET);
46600
46601 /* Initialize index so that we skip internal control keys. */
46602 duk_push_int(ctx, DUK__ENUM_START_INDEX);
46603 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
46604
46605 /*
46606 * Proxy object handling
46607 */
46608
46609#if defined(DUK_USE_ES6_PROXY)
46610 if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
46611 goto skip_proxy;
46612 }
46613 if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
46614 enum_target,
46615 &h_proxy_target,
46616 &h_proxy_handler))) {
46617 goto skip_proxy;
46618 }
46619
46620 DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
46621 duk_push_hobject(ctx, h_proxy_handler);
46622 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ENUMERATE)) {
46623 /* No need to replace the 'enum_target' value in stack, only the
46624 * enum_target reference. This also ensures that the original
46625 * enum target is reachable, which keeps the proxy and the proxy
46626 * target reachable. We do need to replace the internal _Target.
46627 */
46628 DUK_DDD(DUK_DDDPRINT("no enumerate trap, enumerate proxy target instead"));
46629 DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
46630 enum_target = h_proxy_target;
46631
46632 duk_push_hobject(ctx, enum_target); /* -> [ ... enum_target res handler undefined target ] */
46633 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_INT_TARGET);
46634
46635 duk_pop_2(ctx); /* -> [ ... enum_target res ] */
46636 goto skip_proxy;
46637 }
46638
46639 /* [ ... enum_target res handler trap ] */
46640 duk_insert(ctx, -2);
46641 duk_push_hobject(ctx, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
46642 duk_call_method(ctx, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
46643 h_trap_result = duk_require_hobject(ctx, -1);
46644 DUK_UNREF(h_trap_result);
46645
46646 /* Copy trap result keys into the enumerator object. */
46647 len = (duk_uint_fast32_t) duk_get_length(ctx, -1);
46648 for (i = 0; i < len; i++) {
46649 /* XXX: not sure what the correct semantic details are here,
46650 * e.g. handling of missing values (gaps), handling of non-array
46651 * trap results, etc.
46652 *
46653 * For keys, we simply skip non-string keys which seems to be
46654 * consistent with how e.g. Object.keys() will process proxy trap
46655 * results (ES6, Section 19.1.2.14).
46656 */
46657 if (duk_get_prop_index(ctx, -1, i) && duk_is_string(ctx, -1)) {
46658 /* [ ... enum_target res trap_result val ] */
46659 duk_push_true(ctx);
46660 /* [ ... enum_target res trap_result val true ] */
46661 duk_put_prop(ctx, -4);
46662 } else {
46663 duk_pop(ctx);
46664 }
46665 }
46666 /* [ ... enum_target res trap_result ] */
46667 duk_pop(ctx);
46668 duk_remove(ctx, -2);
46669
46670 /* [ ... res ] */
46671
46672 /* The internal _Target property is kept pointing to the original
46673 * enumeration target (the proxy object), so that the enumerator
46674 * 'next' operation can read property values if so requested. The
46675 * fact that the _Target is a proxy disables key existence check
46676 * during enumeration.
46677 */
46678 DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res));
46679 goto compact_and_return;
46680
46681 skip_proxy:
46682#endif /* DUK_USE_ES6_PROXY */
46683
46684 curr = enum_target;
46685 while (curr) {
46686 /*
46687 * Virtual properties.
46688 *
46689 * String and buffer indices are virtual and always enumerable,
46690 * 'length' is virtual and non-enumerable. Array and arguments
46691 * object props have special behavior but are concrete.
46692 */
46693
46694 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) ||
46695 DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
46696 /* String and buffer enumeration behavior is identical now,
46697 * so use shared handler.
46698 */
46699 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
46700 duk_hstring *h_val;
46701 h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
46702 DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
46703 len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
46704 } else {
46705 duk_hbufferobject *h_bufobj;
46706 DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT(curr));
46707 h_bufobj = (duk_hbufferobject *) curr;
46708 if (h_bufobj == NULL) {
46709 /* Neutered buffer, zero length seems
46710 * like good behavior here.
46711 */
46712 len = 0;
46713 } else {
46714 /* There's intentionally no check for
46715 * current underlying buffer length.
46716 */
46717 len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
46718 }
46719 }
46720
46721 for (i = 0; i < len; i++) {
46722 duk_hstring *k;
46723
46724 k = duk_heap_string_intern_u32_checked(thr, i);
46725 DUK_ASSERT(k);
46726 duk_push_hstring(ctx, k);
46727 duk_push_true(ctx);
46728
46729 /* [enum_target res key true] */
46730 duk_put_prop(ctx, -3);
46731
46732 /* [enum_target res] */
46733 }
46734
46735 /* 'length' and other virtual properties are not
46736 * enumerable, but are included if non-enumerable
46737 * properties are requested.
46738 */
46739
46740 if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
46741 duk_uint_fast32_t n;
46742
46743 if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
46744 n = sizeof(duk__bufferobject_virtual_props) / sizeof(duk_uint16_t);
46745 } else {
46746 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr));
46747 DUK_ASSERT(duk__bufferobject_virtual_props[0] == DUK_STRIDX_LENGTH);
46748 n = 1; /* only 'length' */
46749 }
46750
46751 for (i = 0; i < n; i++) {
46752 duk_push_hstring_stridx(ctx, duk__bufferobject_virtual_props[i]);
46753 duk_push_true(ctx);
46754 duk_put_prop(ctx, -3);
46755 }
46756
46757 }
46758 } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(curr)) {
46759 if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
46760 duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
46761 duk_push_true(ctx);
46762 duk_put_prop(ctx, -3);
46763 }
46764 }
46765
46766 /*
46767 * Array part
46768 *
46769 * Note: ordering between array and entry part must match 'abandon array'
46770 * behavior in duk_hobject_props.c: key order after an array is abandoned
46771 * must be the same.
46772 */
46773
46774 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
46775 duk_hstring *k;
46776 duk_tval *tv;
46777
46778 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i);
46779 if (DUK_TVAL_IS_UNUSED(tv)) {
46780 continue;
46781 }
46782 k = duk_heap_string_intern_u32_checked(thr, i);
46783 DUK_ASSERT(k);
46784
46785 duk_push_hstring(ctx, k);
46786 duk_push_true(ctx);
46787
46788 /* [enum_target res key true] */
46789 duk_put_prop(ctx, -3);
46790
46791 /* [enum_target res] */
46792 }
46793
46794 /*
46795 * Entries part
46796 */
46797
46798 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) {
46799 duk_hstring *k;
46800
46801 k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i);
46802 if (!k) {
46803 continue;
46804 }
46805 if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i) &&
46806 !(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
46807 continue;
46808 }
46809 if (DUK_HSTRING_HAS_INTERNAL(k) &&
46810 !(enum_flags & DUK_ENUM_INCLUDE_INTERNAL)) {
46811 continue;
46812 }
46813 if ((enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) &&
46814 (DUK_HSTRING_GET_ARRIDX_SLOW(k) == DUK_HSTRING_NO_ARRAY_INDEX)) {
46815 continue;
46816 }
46817
46818 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
46819 !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
46820
46821 duk_push_hstring(ctx, k);
46822 duk_push_true(ctx);
46823
46824 /* [enum_target res key true] */
46825 duk_put_prop(ctx, -3);
46826
46827 /* [enum_target res] */
46828 }
46829
46830 if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
46831 break;
46832 }
46833
46834 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
46835 }
46836
46837 /* [enum_target res] */
46838
46839 duk_remove(ctx, -2);
46840
46841 /* [res] */
46842
46843 if ((enum_flags & (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) ==
46844 (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) {
46845 /*
46846 * Some E5/E5.1 algorithms require that array indices are iterated
46847 * in a strictly ascending order. This is the case for e.g.
46848 * Array.prototype.forEach() and JSON.stringify() PropertyList
46849 * handling.
46850 *
46851 * To ensure this property for arrays with an array part (and
46852 * arbitrary objects too, since e.g. forEach() can be applied
46853 * to an array), the caller can request that we sort the keys
46854 * here.
46855 */
46856
46857 /* XXX: avoid this at least when enum_target is an Array, it has an
46858 * array part, and no ancestor properties were included? Not worth
46859 * it for JSON, but maybe worth it for forEach().
46860 */
46861
46862 /* XXX: may need a 'length' filter for forEach()
46863 */
46864 DUK_DDD(DUK_DDDPRINT("sort array indices by caller request"));
46865 duk__sort_array_indices(thr, res);
46866 }
46867
46868#if defined(DUK_USE_ES6_PROXY)
46869 compact_and_return:
46870#endif
46871 /* compact; no need to seal because object is internal */
46872 duk_hobject_compact_props(thr, res);
46873
46874 DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
46875}
46876
46877/*
46878 * Returns non-zero if a key and/or value was enumerated, and:
46879 *
46880 * [enum] -> [key] (get_value == 0)
46881 * [enum] -> [key value] (get_value == 1)
46882 *
46883 * Returns zero without pushing anything on the stack otherwise.
46884 */
46885DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value) {
46886 duk_hthread *thr = (duk_hthread *) ctx;
46887 duk_hobject *e;
46888 duk_hobject *enum_target;
46889 duk_hstring *res = NULL;
46890 duk_uint_fast32_t idx;
46891 duk_bool_t check_existence;
46892
46893 DUK_ASSERT(ctx != NULL);
46894
46895 /* [... enum] */
46896
46897 e = duk_require_hobject(ctx, -1);
46898
46899 /* XXX use get tval ptr, more efficient */
46900 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_NEXT);
46901 idx = (duk_uint_fast32_t) duk_require_uint(ctx, -1);
46902 duk_pop(ctx);
46903 DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
46904
46905 /* Enumeration keys are checked against the enumeration target (to see
46906 * that they still exist). In the proxy enumeration case _Target will
46907 * be the proxy, and checking key existence against the proxy is not
46908 * required (or sensible, as the keys may be fully virtual).
46909 */
46910 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);
46911 enum_target = duk_require_hobject(ctx, -1);
46912 DUK_ASSERT(enum_target != NULL);
46913#if defined(DUK_USE_ES6_PROXY)
46914 check_existence = (!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(enum_target));
46915#else
46916 check_existence = 1;
46917#endif
46918 duk_pop(ctx); /* still reachable */
46919
46920 DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
46921 (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(ctx, -1)));
46922
46923 /* no array part */
46924 for (;;) {
46925 duk_hstring *k;
46926
46927 if (idx >= DUK_HOBJECT_GET_ENEXT(e)) {
46928 DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements"));
46929 break;
46930 }
46931
46932 /* we know these because enum objects are internally created */
46933 k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx);
46934 DUK_ASSERT(k != NULL);
46935 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx));
46936 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v));
46937
46938 idx++;
46939
46940 /* recheck that the property still exists */
46941 if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) {
46942 DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip"));
46943 continue;
46944 }
46945
46946 DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k));
46947 res = k;
46948 break;
46949 }
46950
46951 DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
46952
46953 duk_push_u32(ctx, (duk_uint32_t) idx);
46954 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
46955
46956 /* [... enum] */
46957
46958 if (res) {
46959 duk_push_hstring(ctx, res);
46960 if (get_value) {
46961 duk_push_hobject(ctx, enum_target);
46962 duk_dup(ctx, -2); /* -> [... enum key enum_target key] */
46963 duk_get_prop(ctx, -2); /* -> [... enum key enum_target val] */
46964 duk_remove(ctx, -2); /* -> [... enum key val] */
46965 duk_remove(ctx, -3); /* -> [... key val] */
46966 } else {
46967 duk_remove(ctx, -2); /* -> [... key] */
46968 }
46969 return 1;
46970 } else {
46971 duk_pop(ctx); /* -> [...] */
46972 return 0;
46973 }
46974}
46975
46976/*
46977 * Get enumerated keys in an Ecmascript array. Matches Object.keys() behavior
46978 * described in E5 Section 15.2.3.14.
46979 */
46980
46981DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags) {
46982 duk_hthread *thr = (duk_hthread *) ctx;
46983 duk_hobject *e;
46984 duk_uint_fast32_t i;
46985 duk_uint_fast32_t idx;
46986
46987 DUK_ASSERT(ctx != NULL);
46988 DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL);
46989 DUK_UNREF(thr);
46990
46991 /* Create a temporary enumerator to get the (non-duplicated) key list;
46992 * the enumerator state is initialized without being needed, but that
46993 * has little impact.
46994 */
46995
46996 duk_hobject_enumerator_create(ctx, enum_flags);
46997 duk_push_array(ctx);
46998
46999 /* [enum_target enum res] */
47000
47001 e = duk_require_hobject(ctx, -2);
47002 DUK_ASSERT(e != NULL);
47003
47004 idx = 0;
47005 for (i = DUK__ENUM_START_INDEX; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(e); i++) {
47006 duk_hstring *k;
47007
47008 k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, i);
47009 DUK_ASSERT(k); /* enumerator must have no keys deleted */
47010
47011 /* [enum_target enum res] */
47012 duk_push_hstring(ctx, k);
47013 duk_put_prop_index(ctx, -2, idx);
47014 idx++;
47015 }
47016
47017 /* [enum_target enum res] */
47018 duk_remove(ctx, -2);
47019
47020 /* [enum_target res] */
47021
47022 return 1; /* return 1 to allow callers to tail call */
47023}
47024#line 1 "duk_hobject_finalizer.c"
47025/*
47026 * Run an duk_hobject finalizer. Used for both reference counting
47027 * and mark-and-sweep algorithms. Must never throw an error.
47028 *
47029 * There is no return value. Any return value or error thrown by
47030 * the finalizer is ignored (although errors are debug logged).
47031 *
47032 * Notes:
47033 *
47034 * - The thread used for calling the finalizer is the same as the
47035 * 'thr' argument. This may need to change later.
47036 *
47037 * - The finalizer thread 'top' assertions are there because it is
47038 * critical that strict stack policy is observed (i.e. no cruft
47039 * left on the finalizer stack).
47040 */
47041
47042/* include removed: duk_internal.h */
47043
47044DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) {
47045 duk_hthread *thr;
47046
47047 DUK_ASSERT(ctx != NULL);
47048 thr = (duk_hthread *) ctx;
47049
47050 DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
47051
47052 /* [... obj] */
47053
47054 /* XXX: Finalizer lookup should traverse the prototype chain (to allow
47055 * inherited finalizers) but should not invoke accessors or proxy object
47056 * behavior. At the moment this lookup will invoke proxy behavior, so
47057 * caller must ensure that this function is not called if the target is
47058 * a Proxy.
47059 */
47060
47061 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
47062 if (!duk_is_callable(ctx, -1)) {
47063 DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable"));
47064 return 0;
47065 }
47066 duk_dup(ctx, -2);
47067 duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
47068 DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer"));
47069 duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
47070 DUK_DDD(DUK_DDDPRINT("finalizer finished successfully"));
47071 return 0;
47072
47073 /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
47074 * so we don't need to pop stuff here. There is no return value;
47075 * caller determines rescued status based on object refcount.
47076 */
47077}
47078
47079DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) {
47080 duk_context *ctx = (duk_context *) thr;
47081 duk_ret_t rc;
47082#ifdef DUK_USE_ASSERTIONS
47083 duk_idx_t entry_top;
47084#endif
47085
47086 DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj));
47087
47088 DUK_ASSERT(thr != NULL);
47089 DUK_ASSERT(ctx != NULL);
47090 DUK_ASSERT(obj != NULL);
47091 DUK_ASSERT_VALSTACK_SPACE(thr, 1);
47092
47093#ifdef DUK_USE_ASSERTIONS
47094 entry_top = duk_get_top(ctx);
47095#endif
47096 /*
47097 * Get and call the finalizer. All of this must be wrapped
47098 * in a protected call, because even getting the finalizer
47099 * may trigger an error (getter may throw one, for instance).
47100 */
47101
47102 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
47103 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
47104 DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
47105 return;
47106 }
47107 DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
47108 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
47109 /* This shouldn't happen; call sites should avoid looking up
47110 * _Finalizer "through" a Proxy, but ignore if we come here
47111 * with a Proxy to avoid finalizer re-entry.
47112 */
47113 DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call"));
47114 return;
47115 }
47116
47117 /* XXX: use a NULL error handler for the finalizer call? */
47118
47119 DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper"));
47120 duk_push_hobject(ctx, obj); /* this also increases refcount by one */
47121 rc = duk_safe_call(ctx, duk__finalize_helper, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
47122 DUK_ASSERT_TOP(ctx, entry_top + 2); /* duk_safe_call discipline */
47123
47124 if (rc != DUK_EXEC_SUCCESS) {
47125 /* Note: we ask for one return value from duk_safe_call to get this
47126 * error debugging here.
47127 */
47128 DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
47129 (void *) obj, (duk_tval *) duk_get_tval(ctx, -1)));
47130 }
47131 duk_pop_2(ctx); /* -> [...] */
47132
47133 DUK_ASSERT_TOP(ctx, entry_top);
47134}
47135#line 1 "duk_hobject_misc.c"
47136/*
47137 * Misc support functions
47138 */
47139
47140/* include removed: duk_internal.h */
47141
47142DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
47143 duk_uint_t sanity;
47144
47145 DUK_ASSERT(thr != NULL);
47146
47147 /* False if the object is NULL or the prototype 'p' is NULL.
47148 * In particular, false if both are NULL (don't compare equal).
47149 */
47150 if (h == NULL || p == NULL) {
47151 return 0;
47152 }
47153
47154 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
47155 do {
47156 if (h == p) {
47157 return 1;
47158 }
47159
47160 if (sanity-- == 0) {
47161 if (ignore_loop) {
47162 break;
47163 } else {
47164 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
47165 }
47166 }
47167 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
47168 } while (h);
47169
47170 return 0;
47171}
47172
47173DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
47174#ifdef DUK_USE_REFERENCE_COUNTING
47175 duk_hobject *tmp;
47176
47177 DUK_ASSERT(h);
47178 tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
47179 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
47180 DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
47181 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
47182#else
47183 DUK_ASSERT(h);
47184 DUK_UNREF(thr);
47185 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
47186#endif
47187}
47188#line 1 "duk_hobject_pc2line.c"
47189/*
47190 * Helpers for creating and querying pc2line debug data, which
47191 * converts a bytecode program counter to a source line number.
47192 *
47193 * The run-time pc2line data is bit-packed, and documented in:
47194 *
47195 * doc/function-objects.rst
47196 */
47197
47198/* include removed: duk_internal.h */
47199
47200#if defined(DUK_USE_PC2LINE)
47201
47202/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
47203DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
47204 duk_context *ctx = (duk_context *) thr;
47205 duk_hbuffer_dynamic *h_buf;
47206 duk_bitencoder_ctx be_ctx_alloc;
47207 duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
47208 duk_uint32_t *hdr;
47209 duk_size_t new_size;
47210 duk_uint_fast32_t num_header_entries;
47211 duk_uint_fast32_t curr_offset;
47212 duk_int_fast32_t curr_line, next_line, diff_line;
47213 duk_uint_fast32_t curr_pc;
47214 duk_uint_fast32_t hdr_index;
47215
47216 DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
47217
47218 /* XXX: add proper spare handling to dynamic buffer, to minimize
47219 * reallocs; currently there is no spare at all.
47220 */
47221
47222 num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
47223 curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
47224
47225 duk_push_dynamic_buffer(ctx, (duk_size_t) curr_offset);
47226 h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
47227 DUK_ASSERT(h_buf != NULL);
47228 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
47229
47230 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
47231 DUK_ASSERT(hdr != NULL);
47232 hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */
47233
47234 curr_pc = 0U;
47235 while (curr_pc < length) {
47236 new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
47237 duk_hbuffer_resize(thr, h_buf, new_size);
47238
47239 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
47240 DUK_ASSERT(hdr != NULL);
47241 DUK_ASSERT(curr_pc < length);
47242 hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
47243 curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
47244 hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
47245 hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
47246
47247#if 0
47248 DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld",
47249 (long) (curr_pc / DUK_PC2LINE_SKIP),
47250 (long) curr_pc,
47251 (long) hdr[hdr_index + 0],
47252 (long) hdr[hdr_index + 1]));
47253#endif
47254
47255 DUK_MEMZERO(be_ctx, sizeof(*be_ctx));
47256 be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
47257 be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
47258
47259 for (;;) {
47260 curr_pc++;
47261 if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */
47262 (curr_pc >= length) ) { /* end of bytecode */
47263 break;
47264 }
47265 DUK_ASSERT(curr_pc < length);
47266 next_line = (duk_int32_t) instrs[curr_pc].line;
47267 diff_line = next_line - curr_line;
47268
47269#if 0
47270 DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld",
47271 (long) curr_line, (long) next_line, (long) diff_line));
47272#endif
47273
47274 if (diff_line == 0) {
47275 /* 0 */
47276 duk_be_encode(be_ctx, 0, 1);
47277 } else if (diff_line >= 1 && diff_line <= 4) {
47278 /* 1 0 <2 bits> */
47279 duk_be_encode(be_ctx, (0x02 << 2) + (diff_line - 1), 4);
47280 } else if (diff_line >= -0x80 && diff_line <= 0x7f) {
47281 /* 1 1 0 <8 bits> */
47282 DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
47283 duk_be_encode(be_ctx, (0x06 << 8) + (diff_line + 0x80), 11);
47284 } else {
47285 /* 1 1 1 <32 bits>
47286 * Encode in two parts to avoid bitencode 24-bit limitation
47287 */
47288 duk_be_encode(be_ctx, (0x07 << 16) + ((next_line >> 16) & 0xffffU), 19);
47289 duk_be_encode(be_ctx, next_line & 0xffffU, 16);
47290 }
47291
47292 curr_line = next_line;
47293 }
47294
47295 duk_be_finish(be_ctx);
47296 DUK_ASSERT(!be_ctx->truncated);
47297
47298 /* be_ctx->offset == length of encoded bitstream */
47299 curr_offset += (duk_uint_fast32_t) be_ctx->offset;
47300 }
47301
47302 /* compact */
47303 new_size = (duk_size_t) curr_offset;
47304 duk_hbuffer_resize(thr, h_buf, new_size);
47305
47306 (void) duk_to_fixed_buffer(ctx, -1, NULL);
47307
47308 DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
47309 (long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
47310 (duk_tval *) duk_get_tval(ctx, -1)));
47311}
47312
47313/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
47314 * it will map to a large PC which is out of bounds and causes a zero to be
47315 * returned.
47316 */
47317DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
47318 duk_bitdecoder_ctx bd_ctx_alloc;
47319 duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
47320 duk_uint32_t *hdr;
47321 duk_uint_fast32_t start_offset;
47322 duk_uint_fast32_t pc_limit;
47323 duk_uint_fast32_t hdr_index;
47324 duk_uint_fast32_t pc_base;
47325 duk_uint_fast32_t n;
47326 duk_uint_fast32_t curr_line;
47327
47328 DUK_ASSERT(buf != NULL);
47329 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf));
47330 DUK_UNREF(thr);
47331
47332 /*
47333 * Use the index in the header to find the right starting point
47334 */
47335
47336 hdr_index = pc / DUK_PC2LINE_SKIP;
47337 pc_base = hdr_index * DUK_PC2LINE_SKIP;
47338 n = pc - pc_base;
47339
47340 if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
47341 DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
47342 goto error;
47343 }
47344
47345 hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
47346 pc_limit = hdr[0];
47347 if (pc >= pc_limit) {
47348 /* Note: pc is unsigned and cannot be negative */
47349 DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
47350 (long) pc, (long) pc_limit));
47351 goto error;
47352 }
47353
47354 curr_line = hdr[1 + hdr_index * 2];
47355 start_offset = hdr[1 + hdr_index * 2 + 1];
47356 if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
47357 DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
47358 (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
47359 goto error;
47360 }
47361
47362 /*
47363 * Iterate the bitstream (line diffs) until PC is reached
47364 */
47365
47366 DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx));
47367 bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
47368 bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
47369
47370#if 0
47371 DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld",
47372 (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset));
47373#endif
47374
47375 while (n > 0) {
47376#if 0
47377 DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line));
47378#endif
47379
47380 if (duk_bd_decode_flag(bd_ctx)) {
47381 if (duk_bd_decode_flag(bd_ctx)) {
47382 if (duk_bd_decode_flag(bd_ctx)) {
47383 /* 1 1 1 <32 bits> */
47384 duk_uint_fast32_t t;
47385 t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */
47386 t = (t << 16) + duk_bd_decode(bd_ctx, 16);
47387 curr_line = t;
47388 } else {
47389 /* 1 1 0 <8 bits> */
47390 duk_uint_fast32_t t;
47391 t = duk_bd_decode(bd_ctx, 8);
47392 curr_line = curr_line + t - 0x80;
47393 }
47394 } else {
47395 /* 1 0 <2 bits> */
47396 duk_uint_fast32_t t;
47397 t = duk_bd_decode(bd_ctx, 2);
47398 curr_line = curr_line + t + 1;
47399 }
47400 } else {
47401 /* 0: no change */
47402 }
47403
47404 n--;
47405 }
47406
47407 DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
47408 return curr_line;
47409
47410 error:
47411 DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
47412 return 0;
47413}
47414
47415DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc) {
47416 duk_hbuffer_fixed *pc2line;
47417 duk_uint_fast32_t line;
47418
47419 /* XXX: now that pc2line is used by the debugger quite heavily in
47420 * checked execution, this should be optimized to avoid value stack
47421 * and perhaps also implement some form of pc2line caching (see
47422 * future work in debugger.rst).
47423 */
47424
47425 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_PC2LINE);
47426 pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
47427 if (pc2line != NULL) {
47428 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
47429 line = duk__hobject_pc2line_query_raw((duk_hthread *) ctx, pc2line, (duk_uint_fast32_t) pc);
47430 } else {
47431 line = 0;
47432 }
47433 duk_pop(ctx);
47434
47435 return line;
47436}
47437
47438#endif /* DUK_USE_PC2LINE */
47439#line 1 "duk_hobject_props.c"
47440/*
47441 * Hobject property set/get functionality.
47442 *
47443 * This is very central functionality for size, performance, and compliance.
47444 * It is also rather intricate; see hobject-algorithms.rst for discussion on
47445 * the algorithms and memory-management.rst for discussion on refcounts and
47446 * side effect issues.
47447 *
47448 * Notes:
47449 *
47450 * - It might be tempting to assert "refcount nonzero" for objects
47451 * being operated on, but that's not always correct: objects with
47452 * a zero refcount may be operated on by the refcount implementation
47453 * (finalization) for instance. Hence, no refcount assertions are made.
47454 *
47455 * - Many operations (memory allocation, identifier operations, etc)
47456 * may cause arbitrary side effects (e.g. through GC and finalization).
47457 * These side effects may invalidate duk_tval pointers which point to
47458 * areas subject to reallocation (like value stack). Heap objects
47459 * themselves have stable pointers. Holding heap object pointers or
47460 * duk_tval copies is not problematic with respect to side effects;
47461 * care must be taken when holding and using argument duk_tval pointers.
47462 *
47463 * - If a finalizer is executed, it may operate on the the same object
47464 * we're currently dealing with. For instance, the finalizer might
47465 * delete a certain property which has already been looked up and
47466 * confirmed to exist. Ideally finalizers would be disabled if GC
47467 * happens during property access. At the moment property table realloc
47468 * disables finalizers, and all DECREFs may cause arbitrary changes so
47469 * handle DECREF carefully.
47470 *
47471 * - The order of operations for a DECREF matters. When DECREF is executed,
47472 * the entire object graph must be consistent; note that a refzero may
47473 * lead to a mark-and-sweep through a refcount finalizer.
47474 */
47475
47476/*
47477 * XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t
47478 * might be more appropriate.
47479 */
47480
47481/*
47482 * XXX: duk_uint_fast32_t should probably be used in many places here.
47483 */
47484
47485/* include removed: duk_internal.h */
47486
47487/*
47488 * Local defines
47489 */
47490
47491#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX
47492
47493/* hash probe sequence */
47494#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size))
47495#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash))
47496
47497/* marker values for hash part */
47498#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED
47499#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
47500
47501/* valstack space that suffices for all local calls, including recursion
47502 * of other than Duktape calls (getters etc)
47503 */
47504#define DUK__VALSTACK_SPACE 10
47505
47506/* valstack space allocated especially for proxy lookup which does a
47507 * recursive property lookup
47508 */
47509#define DUK__VALSTACK_PROXY_LOOKUP 20
47510
47511/*
47512 * Local prototypes
47513 */
47514
47515DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
47516DUK_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);
47517DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
47518
47519DUK_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);
47520DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj);
47521
47522DUK_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);
47523DUK_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);
47524DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc);
47525
47526/*
47527 * Misc helpers
47528 */
47529
47530/* Convert a duk_tval number (caller checks) to a 32-bit index. Returns
47531 * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array
47532 * index.
47533 */
47534/* XXX: for fastints, could use a variant which assumes a double duk_tval
47535 * (and doesn't need to check for fastint again).
47536 */
47537DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) {
47538 duk_double_t dbl;
47539 duk_uint32_t idx;
47540
47541 DUK_ASSERT(tv != NULL);
47542 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
47543
47544 /* -0 is accepted here as index 0 because ToString(-0) == "0" which is
47545 * in canonical form and thus an array index.
47546 */
47547 dbl = DUK_TVAL_GET_NUMBER(tv);
47548 idx = (duk_uint32_t) dbl;
47549 if ((duk_double_t) idx == dbl) {
47550 /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF,
47551 * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX.
47552 */
47553 return idx;
47554 }
47555 return DUK__NO_ARRAY_INDEX;
47556}
47557
47558#if defined(DUK_USE_FASTINT)
47559/* Convert a duk_tval fastint (caller checks) to a 32-bit index. */
47560DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
47561 duk_int64_t t;
47562
47563 DUK_ASSERT(tv != NULL);
47564 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
47565
47566 t = DUK_TVAL_GET_FASTINT(tv);
47567 if ((t & ~0xffffffffULL) != 0) {
47568 /* Catches >0x100000000 and negative values. */
47569 return DUK__NO_ARRAY_INDEX;
47570 }
47571
47572 /* If the value happens to be 0xFFFFFFFF, it's not a valid array index
47573 * but will then match DUK__NO_ARRAY_INDEX.
47574 */
47575 return (duk_uint32_t) t;
47576}
47577#endif /* DUK_USE_FASTINT */
47578
47579/* Push an arbitrary duk_tval to the stack, coerce it to string, and return
47580 * both a duk_hstring pointer and an array index (or DUK__NO_ARRAY_INDEX).
47581 */
47582DUK_LOCAL duk_uint32_t duk__push_tval_to_hstring_arr_idx(duk_context *ctx, duk_tval *tv, duk_hstring **out_h) {
47583 duk_uint32_t arr_idx;
47584 duk_hstring *h;
47585
47586 DUK_ASSERT(ctx != NULL);
47587 DUK_ASSERT(tv != NULL);
47588 DUK_ASSERT(out_h != NULL);
47589
47590 duk_push_tval(ctx, tv);
47591 duk_to_string(ctx, -1);
47592 h = duk_get_hstring(ctx, -1);
47593 DUK_ASSERT(h != NULL);
47594 *out_h = h;
47595
47596 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h);
47597 return arr_idx;
47598}
47599
47600/* String is an own (virtual) property of a lightfunc. */
47601DUK_LOCAL duk_bool_t duk__key_is_lightfunc_ownprop(duk_hthread *thr, duk_hstring *key) {
47602 DUK_UNREF(thr);
47603 return (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
47604 key == DUK_HTHREAD_STRING_NAME(thr));
47605}
47606
47607/*
47608 * Helpers for managing property storage size
47609 */
47610
47611/* Get default hash part size for a certain entry part size. */
47612#if defined(DUK_USE_HOBJECT_HASH_PART)
47613DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
47614 DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
47615
47616 if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
47617 duk_uint32_t res;
47618
47619 /* result: hash_prime(floor(1.2 * e_size)) */
47620 res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR);
47621
47622 /* if fails, e_size will be zero = not an issue, except performance-wise */
47623 DUK_ASSERT(res == 0 || res > e_size);
47624 return res;
47625 } else {
47626 return 0;
47627 }
47628}
47629#endif /* USE_PROP_HASH_PART */
47630
47631/* Get minimum entry part growth for a certain size. */
47632DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
47633 duk_uint32_t res;
47634
47635 DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
47636
47637 res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR;
47638 DUK_ASSERT(res >= 1); /* important for callers */
47639 return res;
47640}
47641
47642/* Get minimum array part growth for a certain size. */
47643DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) {
47644 duk_uint32_t res;
47645
47646 DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES);
47647
47648 res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR;
47649 DUK_ASSERT(res >= 1); /* important for callers */
47650 return res;
47651}
47652
47653/* Count actually used entry part entries (non-NULL keys). */
47654DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) {
47655 duk_uint_fast32_t i;
47656 duk_uint_fast32_t n = 0;
47657 duk_hstring **e;
47658
47659 DUK_ASSERT(obj != NULL);
47660 DUK_UNREF(thr);
47661
47662 e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj);
47663 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
47664 if (*e++) {
47665 n++;
47666 }
47667 }
47668 return (duk_uint32_t) n;
47669}
47670
47671/* Count actually used array part entries and array minimum size.
47672 * NOTE: 'out_min_size' can be computed much faster by starting from the
47673 * end and breaking out early when finding first used entry, but this is
47674 * not needed now.
47675 */
47676DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) {
47677 duk_uint_fast32_t i;
47678 duk_uint_fast32_t used = 0;
47679 duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1; /* see below */
47680 duk_tval *a;
47681
47682 DUK_ASSERT(obj != NULL);
47683 DUK_ASSERT(out_used != NULL);
47684 DUK_ASSERT(out_min_size != NULL);
47685 DUK_UNREF(thr);
47686
47687 a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj);
47688 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
47689 duk_tval *tv = a++;
47690 if (!DUK_TVAL_IS_UNUSED(tv)) {
47691 used++;
47692 highest_idx = i;
47693 }
47694 }
47695
47696 /* Initial value for highest_idx is -1 coerced to unsigned. This
47697 * is a bit odd, but (highest_idx + 1) will then wrap to 0 below
47698 * for out_min_size as intended.
47699 */
47700
47701 *out_used = used;
47702 *out_min_size = highest_idx + 1; /* 0 if no used entries */
47703}
47704
47705/* Check array density and indicate whether or not the array part should be abandoned. */
47706DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) {
47707 /*
47708 * Array abandon check; abandon if:
47709 *
47710 * new_used / new_size < limit
47711 * new_used < limit * new_size || limit is 3 bits fixed point
47712 * new_used < limit' / 8 * new_size || *8
47713 * 8*new_used < limit' * new_size || :8
47714 * new_used < limit' * (new_size / 8)
47715 *
47716 * Here, new_used = a_used, new_size = a_size.
47717 *
47718 * Note: some callers use approximate values for a_used and/or a_size
47719 * (e.g. dropping a '+1' term). This doesn't affect the usefulness
47720 * of the check, but may confuse debugging.
47721 */
47722
47723 return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3));
47724}
47725
47726/* Fast check for extending array: check whether or not a slow density check is required. */
47727DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) {
47728 /*
47729 * In a fast check we assume old_size equals old_used (i.e., existing
47730 * array is fully dense).
47731 *
47732 * Slow check if:
47733 *
47734 * (new_size - old_size) / old_size > limit
47735 * new_size - old_size > limit * old_size
47736 * new_size > (1 + limit) * old_size || limit' is 3 bits fixed point
47737 * new_size > (1 + (limit' / 8)) * old_size || * 8
47738 * 8 * new_size > (8 + limit') * old_size || : 8
47739 * new_size > (8 + limit') * (old_size / 8)
47740 * new_size > limit'' * (old_size / 8) || limit'' = 9 -> max 25% increase
47741 * arr_idx + 1 > limit'' * (old_size / 8)
47742 *
47743 * This check doesn't work well for small values, so old_size is rounded
47744 * up for the check (and the '+ 1' of arr_idx can be ignored in practice):
47745 *
47746 * arr_idx > limit'' * ((old_size + 7) / 8)
47747 */
47748
47749 return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
47750}
47751
47752/*
47753 * Proxy helpers
47754 */
47755
47756#if defined(DUK_USE_ES6_PROXY)
47757DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
47758 duk_tval *tv_target;
47759 duk_tval *tv_handler;
47760 duk_hobject *h_target;
47761 duk_hobject *h_handler;
47762
47763 DUK_ASSERT(thr != NULL);
47764 DUK_ASSERT(obj != NULL);
47765 DUK_ASSERT(out_target != NULL);
47766 DUK_ASSERT(out_handler != NULL);
47767
47768 /* Caller doesn't need to check exotic proxy behavior (but does so for
47769 * some fast paths).
47770 */
47771 if (DUK_LIKELY(!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
47772 return 0;
47773 }
47774
47775 tv_handler = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_HANDLER(thr));
47776 if (!tv_handler) {
47777 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
47778 return 0;
47779 }
47780 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_handler));
47781 h_handler = DUK_TVAL_GET_OBJECT(tv_handler);
47782 DUK_ASSERT(h_handler != NULL);
47783 *out_handler = h_handler;
47784 tv_handler = NULL; /* avoid issues with relocation */
47785
47786 tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_TARGET(thr));
47787 if (!tv_target) {
47788 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
47789 return 0;
47790 }
47791 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
47792 h_target = DUK_TVAL_GET_OBJECT(tv_target);
47793 DUK_ASSERT(h_target != NULL);
47794 *out_target = h_target;
47795 tv_target = NULL; /* avoid issues with relocation */
47796
47797 return 1;
47798}
47799#endif /* DUK_USE_ES6_PROXY */
47800
47801/* Get Proxy target object. If the argument is not a Proxy, return it as is.
47802 * If a Proxy is revoked, an error is thrown.
47803 */
47804#if defined(DUK_USE_ES6_PROXY)
47805DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj) {
47806 duk_hobject *h_target;
47807 duk_hobject *h_handler;
47808
47809 DUK_ASSERT(thr != NULL);
47810 DUK_ASSERT(obj != NULL);
47811
47812 /* Resolve Proxy targets until Proxy chain ends. No explicit check for
47813 * a Proxy loop: user code cannot create such a loop without tweaking
47814 * internal properties directly.
47815 */
47816
47817 while (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
47818 if (duk_hobject_proxy_check(thr, obj, &h_target, &h_handler)) {
47819 DUK_ASSERT(h_target != NULL);
47820 obj = h_target;
47821 } else {
47822 break;
47823 }
47824 }
47825
47826 DUK_ASSERT(obj != NULL);
47827 return obj;
47828}
47829#endif /* DUK_USE_ES6_PROXY */
47830
47831#if defined(DUK_USE_ES6_PROXY)
47832DUK_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) {
47833 duk_context *ctx = (duk_context *) thr;
47834 duk_hobject *h_handler;
47835
47836 DUK_ASSERT(thr != NULL);
47837 DUK_ASSERT(obj != NULL);
47838 DUK_ASSERT(tv_key != NULL);
47839 DUK_ASSERT(out_target != NULL);
47840
47841 if (!duk_hobject_proxy_check(thr, obj, out_target, &h_handler)) {
47842 return 0;
47843 }
47844 DUK_ASSERT(*out_target != NULL);
47845 DUK_ASSERT(h_handler != NULL);
47846
47847 /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a
47848 * normal property set/get which would allow a proxy handler to interfere with
47849 * such behavior and to get access to internal key strings. This is not a problem
47850 * as such because internal key strings can be created in other ways too (e.g.
47851 * through buffers). The best fix is to change Duktape internal lookups to
47852 * skip proxy behavior. Until that, internal property accesses bypass the
47853 * proxy and are applied to the target (as if the handler did not exist).
47854 * This has some side effects, see test-bi-proxy-internal-keys.js.
47855 */
47856
47857 if (DUK_TVAL_IS_STRING(tv_key)) {
47858 duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key);
47859 DUK_ASSERT(h_key != NULL);
47860 if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
47861 DUK_DDD(DUK_DDDPRINT("internal key, skip proxy handler and apply to target"));
47862 return 0;
47863 }
47864 }
47865
47866 /* The handler is looked up with a normal property lookup; it may be an
47867 * accessor or the handler object itself may be a proxy object. If the
47868 * handler is a proxy, we need to extend the valstack as we make a
47869 * recursive proxy check without a function call in between (in fact
47870 * there is no limit to the potential recursion here).
47871 *
47872 * (For sanity, proxy creation rejects another proxy object as either
47873 * the handler or the target at the moment so recursive proxy cases
47874 * are not realized now.)
47875 */
47876
47877 /* XXX: C recursion limit if proxies are allowed as handler/target values */
47878
47879 duk_require_stack(ctx, DUK__VALSTACK_PROXY_LOOKUP);
47880 duk_push_hobject(ctx, h_handler);
47881 if (duk_get_prop_stridx(ctx, -1, stridx_trap)) {
47882 /* -> [ ... handler trap ] */
47883 duk_insert(ctx, -2); /* -> [ ... trap handler ] */
47884
47885 /* stack prepped for func call: [ ... trap handler ] */
47886 return 1;
47887 } else {
47888 duk_pop_2(ctx);
47889 return 0;
47890 }
47891}
47892#endif /* DUK_USE_ES6_PROXY */
47893
47894/*
47895 * Reallocate property allocation, moving properties to the new allocation.
47896 *
47897 * Includes key compaction, rehashing, and can also optionally abandoning
47898 * the array part, 'migrating' array entries into the beginning of the
47899 * new entry part. Arguments are not validated here, so e.g. new_h_size
47900 * MUST be a valid prime.
47901 *
47902 * There is no support for in-place reallocation or just compacting keys
47903 * without resizing the property allocation. This is intentional to keep
47904 * code size minimal.
47905 *
47906 * The implementation is relatively straightforward, except for the array
47907 * abandonment process. Array abandonment requires that new string keys
47908 * are interned, which may trigger GC. All keys interned so far must be
47909 * reachable for GC at all times; valstack is used for that now.
47910 *
47911 * Also, a GC triggered during this reallocation process must not interfere
47912 * with the object being resized. This is currently controlled by using
47913 * heap->mark_and_sweep_base_flags to indicate that no finalizers will be
47914 * executed (as they can affect ANY object) and no objects are compacted
47915 * (it would suffice to protect this particular object only, though).
47916 *
47917 * Note: a non-checked variant would be nice but is a bit tricky to
47918 * implement for the array abandonment process. It's easy for
47919 * everything else.
47920 *
47921 * Note: because we need to potentially resize the valstack (as part
47922 * of abandoning the array part), any tval pointers to the valstack
47923 * will become invalid after this call.
47924 */
47925
47926DUK_LOCAL
47927void duk__realloc_props(duk_hthread *thr,
47928 duk_hobject *obj,
47929 duk_uint32_t new_e_size,
47930 duk_uint32_t new_a_size,
47931 duk_uint32_t new_h_size,
47932 duk_bool_t abandon_array) {
47933 duk_context *ctx = (duk_context *) thr;
47934#ifdef DUK_USE_MARK_AND_SWEEP
47935 duk_small_uint_t prev_mark_and_sweep_base_flags;
47936#endif
47937 duk_uint32_t new_alloc_size;
47938 duk_uint32_t new_e_size_adjusted;
47939 duk_uint8_t *new_p;
47940 duk_hstring **new_e_k;
47941 duk_propvalue *new_e_pv;
47942 duk_uint8_t *new_e_f;
47943 duk_tval *new_a;
47944 duk_uint32_t *new_h;
47945 duk_uint32_t new_e_next;
47946 duk_uint_fast32_t i;
47947
47948 DUK_ASSERT(thr != NULL);
47949 DUK_ASSERT(ctx != NULL);
47950 DUK_ASSERT(obj != NULL);
47951 DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */
47952 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
47953 DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); /* required to guarantee success of rehashing,
47954 * intentionally use unadjusted new_e_size
47955 */
47956 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
47957 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
47958
47959 /*
47960 * Pre resize assertions.
47961 */
47962
47963#ifdef DUK_USE_ASSERTIONS
47964 /* XXX: pre-checks (such as no duplicate keys) */
47965#endif
47966
47967 /*
47968 * For property layout 1, tweak e_size to ensure that the whole entry
47969 * part (key + val + flags) is a suitable multiple for alignment
47970 * (platform specific).
47971 *
47972 * Property layout 2 does not require this tweaking and is preferred
47973 * on low RAM platforms requiring alignment.
47974 */
47975
47976#if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3)
47977 DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld", (long) new_e_size));
47978 new_e_size_adjusted = new_e_size;
47979#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1)
47980 DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
47981 new_e_size_adjusted = new_e_size;
47982#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
47983 new_e_size_adjusted = (new_e_size + DUK_HOBJECT_ALIGN_TARGET - 1) & (~(DUK_HOBJECT_ALIGN_TARGET - 1));
47984 DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
47985 (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
47986 DUK_ASSERT(new_e_size_adjusted >= new_e_size);
47987#else
47988#error invalid hobject layout defines
47989#endif
47990
47991 /*
47992 * Debug logging after adjustment.
47993 */
47994
47995 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 "
47996 "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
47997 (void *) obj,
47998 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
47999 DUK_HOBJECT_GET_ASIZE(obj),
48000 DUK_HOBJECT_GET_HSIZE(obj)),
48001 (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size),
48002 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
48003 (long) DUK_HOBJECT_GET_ESIZE(obj),
48004 (long) DUK_HOBJECT_GET_ENEXT(obj),
48005 (long) DUK_HOBJECT_GET_ASIZE(obj),
48006 (long) DUK_HOBJECT_GET_HSIZE(obj),
48007 (long) new_e_size_adjusted,
48008 (long) new_a_size,
48009 (long) new_h_size,
48010 (long) abandon_array,
48011 (long) new_e_size));
48012
48013 /*
48014 * Property count check. This is the only point where we ensure that
48015 * we don't get more (allocated) property space that we can handle.
48016 * There aren't hard limits as such, but some algorithms fail (e.g.
48017 * finding next higher prime, selecting hash part size) if we get too
48018 * close to the 4G property limit.
48019 *
48020 * Since this works based on allocation size (not actually used size),
48021 * the limit is a bit approximate but good enough in practice.
48022 */
48023
48024 if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
48025 DUK_ERROR_ALLOC_DEFMSG(thr);
48026 }
48027
48028 /*
48029 * Compute new alloc size and alloc new area.
48030 *
48031 * The new area is allocated as a dynamic buffer and placed into the
48032 * valstack for reachability. The actual buffer is then detached at
48033 * the end.
48034 *
48035 * Note: heap_mark_and_sweep_base_flags are altered here to ensure
48036 * no-one touches this object while we're resizing and rehashing it.
48037 * The flags must be reset on every exit path after it. Finalizers
48038 * and compaction is prevented currently for all objects while it
48039 * would be enough to restrict it only for the current object.
48040 */
48041
48042#ifdef DUK_USE_MARK_AND_SWEEP
48043 prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
48044 thr->heap->mark_and_sweep_base_flags |=
48045 DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
48046 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */
48047#endif
48048
48049 new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
48050 DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size));
48051 new_e_next = 0;
48052 new_e_k = NULL;
48053 if (new_alloc_size == 0) {
48054 /* for zero size, don't push anything on valstack */
48055 DUK_ASSERT(new_e_size_adjusted == 0);
48056 DUK_ASSERT(new_a_size == 0);
48057 DUK_ASSERT(new_h_size == 0);
48058 new_p = NULL;
48059 } else {
48060 /* This may trigger mark-and-sweep with arbitrary side effects,
48061 * including an attempted resize of the object we're resizing,
48062 * executing a finalizer which may add or remove properties of
48063 * the object we're resizing etc.
48064 */
48065
48066#if 0 /* XXX: inject test */
48067 if (1) {
48068 goto alloc_failed;
48069 }
48070#endif
48071 new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size);
48072 if (new_p == NULL) {
48073 /* NULL always indicates alloc failure because
48074 * new_alloc_size > 0.
48075 */
48076 goto alloc_failed;
48077 }
48078 }
48079
48080 /* Set up pointers to the new property area: this is hidden behind a macro
48081 * because it is memory layout specific.
48082 */
48083 DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h,
48084 new_e_size_adjusted, new_a_size, new_h_size);
48085 DUK_UNREF(new_h); /* happens when hash part dropped */
48086
48087 /* if new_p == NULL, all of these pointers are NULL */
48088 DUK_ASSERT((new_p != NULL) ||
48089 (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL &&
48090 new_a == NULL && new_h == NULL));
48091
48092 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",
48093 (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f,
48094 (void *) new_a, (void *) new_h));
48095
48096 /*
48097 * Migrate array to start of entries if requested.
48098 *
48099 * Note: from an enumeration perspective the order of entry keys matters.
48100 * Array keys should appear wherever they appeared before the array abandon
48101 * operation.
48102 */
48103
48104 if (abandon_array) {
48105 /*
48106 * Note: assuming new_a_size == 0, and that entry part contains
48107 * no conflicting keys, refcounts do not need to be adjusted for
48108 * the values, as they remain exactly the same.
48109 *
48110 * The keys, however, need to be interned, incref'd, and be
48111 * reachable for GC. Any intern attempt may trigger a GC and
48112 * claim any non-reachable strings, so every key must be reachable
48113 * at all times.
48114 *
48115 * A longjmp must not occur here, as the new_p allocation would
48116 * be freed without these keys being decref'd, hence the messy
48117 * decref handling if intern fails.
48118 */
48119 DUK_ASSERT(new_a_size == 0);
48120
48121 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
48122 duk_tval *tv1;
48123 duk_tval *tv2;
48124 duk_hstring *key;
48125
48126 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48127
48128 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
48129 if (DUK_TVAL_IS_UNUSED(tv1)) {
48130 continue;
48131 }
48132
48133 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
48134 new_e_pv != NULL && new_e_f != NULL);
48135
48136 /*
48137 * Intern key via the valstack to ensure reachability behaves
48138 * properly. We must avoid longjmp's here so use non-checked
48139 * primitives.
48140 *
48141 * Note: duk_check_stack() potentially reallocs the valstack,
48142 * invalidating any duk_tval pointers to valstack. Callers
48143 * must be careful.
48144 */
48145
48146 /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */
48147 if (!duk_check_stack(ctx, 1)) {
48148 goto abandon_error;
48149 }
48150 DUK_ASSERT_VALSTACK_SPACE(thr, 1);
48151 key = duk_heap_string_intern_u32(thr->heap, i);
48152 if (!key) {
48153 goto abandon_error;
48154 }
48155 duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */
48156
48157 /* key is now reachable in the valstack */
48158
48159 DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */
48160 new_e_k[new_e_next] = key;
48161 tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */
48162 DUK_TVAL_SET_TVAL(tv2, tv1);
48163 new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE |
48164 DUK_PROPDESC_FLAG_ENUMERABLE |
48165 DUK_PROPDESC_FLAG_CONFIGURABLE;
48166 new_e_next++;
48167
48168 /* Note: new_e_next matches pushed temp key count, and nothing can
48169 * fail above between the push and this point.
48170 */
48171 }
48172
48173 DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
48174 duk_pop_n(ctx, new_e_next);
48175 }
48176
48177 /*
48178 * Copy keys and values in the entry part (compacting them at the same time).
48179 */
48180
48181 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
48182 duk_hstring *key;
48183
48184 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48185
48186 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
48187 if (!key) {
48188 continue;
48189 }
48190
48191 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
48192 new_e_pv != NULL && new_e_f != NULL);
48193
48194 new_e_k[new_e_next] = key;
48195 new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i);
48196 new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
48197 new_e_next++;
48198 }
48199 /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
48200
48201 /*
48202 * Copy array elements to new array part.
48203 */
48204
48205 if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
48206 /* copy existing entries as is */
48207 DUK_ASSERT(new_p != NULL && new_a != NULL);
48208 if (DUK_HOBJECT_GET_ASIZE(obj) > 0) {
48209 /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
48210 * the 'new_a' pointer will be invalid which is not allowed even
48211 * when copy size is zero.
48212 */
48213 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48214 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0);
48215 DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj));
48216 }
48217
48218 /* fill new entries with -unused- (required, gc reachable) */
48219 for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
48220 duk_tval *tv = &new_a[i];
48221 DUK_TVAL_SET_UNUSED(tv);
48222 }
48223 } else {
48224#ifdef DUK_USE_ASSERTIONS
48225 /* caller must have decref'd values above new_a_size (if that is necessary) */
48226 if (!abandon_array) {
48227 for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
48228 duk_tval *tv;
48229 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
48230
48231 /* current assertion is quite strong: decref's and set to unused */
48232 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
48233 }
48234 }
48235#endif
48236 if (new_a_size > 0) {
48237 /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
48238 * the 'new_a' pointer will be invalid which is not allowed even
48239 * when copy size is zero.
48240 */
48241 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48242 DUK_ASSERT(new_a_size > 0);
48243 DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size);
48244 }
48245 }
48246
48247 /*
48248 * Rebuild the hash part always from scratch (guaranteed to finish).
48249 *
48250 * Any resize of hash part requires rehashing. In addition, by rehashing
48251 * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
48252 * to ensuring the hash part never fills up.
48253 */
48254
48255#if defined(DUK_USE_HOBJECT_HASH_PART)
48256 if (DUK_UNLIKELY(new_h_size > 0)) {
48257 DUK_ASSERT(new_h != NULL);
48258
48259 /* fill new_h with u32 0xff = UNUSED */
48260 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48261 DUK_ASSERT(new_h_size > 0);
48262 DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
48263
48264 DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */
48265 for (i = 0; i < new_e_next; i++) {
48266 duk_hstring *key = new_e_k[i];
48267 duk_uint32_t j, step;
48268
48269 DUK_ASSERT(key != NULL);
48270 j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size);
48271 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
48272
48273 for (;;) {
48274 DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */
48275 if (new_h[j] == DUK__HASH_UNUSED) {
48276 DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
48277 new_h[j] = i;
48278 break;
48279 }
48280 DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
48281 j = (j + step) % new_h_size;
48282
48283 /* guaranteed to finish */
48284 DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size));
48285 }
48286 }
48287 } else {
48288 DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
48289 }
48290#endif /* DUK_USE_HOBJECT_HASH_PART */
48291
48292 /*
48293 * Nice debug log.
48294 */
48295
48296 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 "
48297 "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
48298 (void *) obj,
48299 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
48300 DUK_HOBJECT_GET_ASIZE(obj),
48301 DUK_HOBJECT_GET_HSIZE(obj)),
48302 (long) new_alloc_size,
48303 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
48304 (long) DUK_HOBJECT_GET_ESIZE(obj),
48305 (long) DUK_HOBJECT_GET_ENEXT(obj),
48306 (long) DUK_HOBJECT_GET_ASIZE(obj),
48307 (long) DUK_HOBJECT_GET_HSIZE(obj),
48308 (void *) new_p,
48309 (long) new_e_size_adjusted,
48310 (long) new_e_next,
48311 (long) new_a_size,
48312 (long) new_h_size,
48313 (long) abandon_array,
48314 (long) new_e_size));
48315
48316 /*
48317 * All done, switch properties ('p') allocation to new one.
48318 */
48319
48320 DUK_FREE(thr->heap, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
48321 DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
48322 DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
48323 DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
48324 DUK_HOBJECT_SET_ASIZE(obj, new_a_size);
48325 DUK_HOBJECT_SET_HSIZE(obj, new_h_size);
48326
48327 /* clear array part flag only after switching */
48328 if (abandon_array) {
48329 DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
48330 }
48331
48332 DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj));
48333
48334#ifdef DUK_USE_MARK_AND_SWEEP
48335 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
48336#endif
48337
48338 /*
48339 * Post resize assertions.
48340 */
48341
48342#ifdef DUK_USE_ASSERTIONS
48343 /* XXX: post-checks (such as no duplicate keys) */
48344#endif
48345 return;
48346
48347 /*
48348 * Abandon array failed, need to decref keys already inserted
48349 * into the beginning of new_e_k before unwinding valstack.
48350 */
48351
48352 abandon_error:
48353 alloc_failed:
48354 DUK_D(DUK_DPRINT("object property table resize failed"));
48355
48356 i = new_e_next;
48357 while (i > 0) {
48358 i--;
48359 DUK_ASSERT(new_e_k != NULL);
48360 DUK_ASSERT(new_e_k[i] != NULL);
48361 DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */
48362 }
48363
48364 DUK_FREE(thr->heap, new_p); /* OK for NULL. */
48365
48366#ifdef DUK_USE_MARK_AND_SWEEP
48367 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
48368#endif
48369
48370 DUK_ERROR_ALLOC_DEFMSG(thr);
48371}
48372
48373/*
48374 * Helpers to resize properties allocation on specific needs.
48375 */
48376
48377/* Grow entry part allocation for one additional entry. */
48378DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
48379 duk_uint32_t old_e_used; /* actually used, non-NULL entries */
48380 duk_uint32_t new_e_size;
48381 duk_uint32_t new_a_size;
48382 duk_uint32_t new_h_size;
48383
48384 DUK_ASSERT(thr != NULL);
48385 DUK_ASSERT(obj != NULL);
48386
48387 /* Duktape 0.11.0 and prior tried to optimize the resize by not
48388 * counting the number of actually used keys prior to the resize.
48389 * This worked mostly well but also caused weird leak-like behavior
48390 * as in: test-bug-object-prop-alloc-unbounded.js. So, now we count
48391 * the keys explicitly to compute the new entry part size.
48392 */
48393
48394 old_e_used = duk__count_used_e_keys(thr, obj);
48395 new_e_size = old_e_used + duk__get_min_grow_e(old_e_used);
48396#if defined(DUK_USE_HOBJECT_HASH_PART)
48397 new_h_size = duk__get_default_h_size(new_e_size);
48398#else
48399 new_h_size = 0;
48400#endif
48401 new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
48402 DUK_ASSERT(new_e_size >= old_e_used + 1); /* duk__get_min_grow_e() is always >= 1 */
48403
48404 duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
48405}
48406
48407/* Grow array part for a new highest array index. */
48408DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) {
48409 duk_uint32_t new_e_size;
48410 duk_uint32_t new_a_size;
48411 duk_uint32_t new_h_size;
48412
48413 DUK_ASSERT(thr != NULL);
48414 DUK_ASSERT(obj != NULL);
48415 DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj));
48416
48417 /* minimum new length is highest_arr_idx + 1 */
48418
48419 new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
48420 new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
48421 new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
48422 DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */
48423
48424 duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
48425}
48426
48427/* Abandon array part, moving array entries into entries part.
48428 * This requires a props resize, which is a heavy operation.
48429 * We also compact the entries part while we're at it, although
48430 * this is not strictly required.
48431 */
48432DUK_LOCAL void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) {
48433 duk_uint32_t new_e_size;
48434 duk_uint32_t new_a_size;
48435 duk_uint32_t new_h_size;
48436 duk_uint32_t e_used; /* actually used, non-NULL keys */
48437 duk_uint32_t a_used;
48438 duk_uint32_t a_size;
48439
48440 DUK_ASSERT(thr != NULL);
48441 DUK_ASSERT(obj != NULL);
48442
48443 e_used = duk__count_used_e_keys(thr, obj);
48444 duk__compute_a_stats(thr, obj, &a_used, &a_size);
48445
48446 /*
48447 * Must guarantee all actually used array entries will fit into
48448 * new entry part. Add one growth step to ensure we don't run out
48449 * of space right away.
48450 */
48451
48452 new_e_size = e_used + a_used;
48453 new_e_size = new_e_size + duk__get_min_grow_e(new_e_size);
48454 new_a_size = 0;
48455#if defined(DUK_USE_HOBJECT_HASH_PART)
48456 new_h_size = duk__get_default_h_size(new_e_size);
48457#else
48458 new_h_size = 0;
48459#endif
48460
48461 DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, "
48462 "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; "
48463 "resize to e_size=%ld, a_size=%ld, h_size=%ld",
48464 (void *) obj, (long) e_used, (long) a_used, (long) a_size,
48465 (long) new_e_size, (long) new_a_size, (long) new_h_size));
48466
48467 duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
48468}
48469
48470/*
48471 * Compact an object. Minimizes allocation size for objects which are
48472 * not likely to be extended. This is useful for internal and non-
48473 * extensible objects, but can also be called for non-extensible objects.
48474 * May abandon the array part if it is computed to be too sparse.
48475 *
48476 * This call is relatively expensive, as it needs to scan both the
48477 * entries and the array part.
48478 *
48479 * The call may fail due to allocation error.
48480 */
48481
48482DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) {
48483 duk_uint32_t e_size; /* currently used -> new size */
48484 duk_uint32_t a_size; /* currently required */
48485 duk_uint32_t a_used; /* actually used */
48486 duk_uint32_t h_size;
48487 duk_bool_t abandon_array;
48488
48489 DUK_ASSERT(thr != NULL);
48490 DUK_ASSERT(obj != NULL);
48491
48492#if defined(DUK_USE_ROM_OBJECTS)
48493 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
48494 DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object"));
48495 return;
48496 }
48497#endif
48498
48499 e_size = duk__count_used_e_keys(thr, obj);
48500 duk__compute_a_stats(thr, obj, &a_used, &a_size);
48501
48502 DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, "
48503 "resized array density would be: %ld/%ld = %lf",
48504 (long) e_size, (long) a_used, (long) a_size,
48505 (long) a_used, (long) a_size,
48506 (double) a_used / (double) a_size));
48507
48508 if (duk__abandon_array_density_check(a_used, a_size)) {
48509 DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld",
48510 (long) a_used, (long) a_size));
48511 abandon_array = 1;
48512 e_size += a_used;
48513 a_size = 0;
48514 } else {
48515 DUK_DD(DUK_DDPRINT("decided to keep array during compaction"));
48516 abandon_array = 0;
48517 }
48518
48519#if defined(DUK_USE_HOBJECT_HASH_PART)
48520 if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
48521 h_size = duk__get_default_h_size(e_size);
48522 } else {
48523 h_size = 0;
48524 }
48525#else
48526 h_size = 0;
48527#endif
48528
48529 DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld",
48530 (long) e_size, (long) a_size, (long) h_size, (long) abandon_array));
48531
48532 duk__realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
48533}
48534
48535/*
48536 * Find an existing key from entry part either by linear scan or by
48537 * using the hash index (if it exists).
48538 *
48539 * Sets entry index (and possibly the hash index) to output variables,
48540 * which allows the caller to update the entry and hash entries in-place.
48541 * If entry is not found, both values are set to -1. If entry is found
48542 * but there is no hash part, h_idx is set to -1.
48543 */
48544
48545DUK_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) {
48546 DUK_ASSERT(obj != NULL);
48547 DUK_ASSERT(key != NULL);
48548 DUK_ASSERT(e_idx != NULL);
48549 DUK_ASSERT(h_idx != NULL);
48550 DUK_UNREF(heap);
48551
48552 if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0))
48553 {
48554 /* Linear scan: more likely because most objects are small.
48555 * This is an important fast path.
48556 *
48557 * XXX: this might be worth inlining for property lookups.
48558 */
48559 duk_uint_fast32_t i;
48560 duk_uint_fast32_t n;
48561 duk_hstring **h_keys_base;
48562 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using linear scan for lookup"));
48563
48564 h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj);
48565 n = DUK_HOBJECT_GET_ENEXT(obj);
48566 for (i = 0; i < n; i++) {
48567 if (h_keys_base[i] == key) {
48568 *e_idx = i;
48569 *h_idx = -1;
48570 return;
48571 }
48572 }
48573 }
48574#if defined(DUK_USE_HOBJECT_HASH_PART)
48575 else
48576 {
48577 /* hash lookup */
48578 duk_uint32_t n;
48579 duk_uint32_t i, step;
48580 duk_uint32_t *h_base;
48581
48582 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup"));
48583
48584 h_base = DUK_HOBJECT_H_GET_BASE(heap, obj);
48585 n = DUK_HOBJECT_GET_HSIZE(obj);
48586 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
48587 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
48588
48589 for (;;) {
48590 duk_uint32_t t;
48591
48592 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
48593 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
48594 t = h_base[i];
48595 DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED ||
48596 (t < DUK_HOBJECT_GET_ESIZE(obj))); /* t >= 0 always true, unsigned */
48597
48598 if (t == DUK__HASH_UNUSED) {
48599 break;
48600 } else if (t == DUK__HASH_DELETED) {
48601 DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld",
48602 (long) i, (long) t));
48603 } else {
48604 DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj));
48605 if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
48606 DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
48607 (long) i, (long) t, (void *) key));
48608 *e_idx = t;
48609 *h_idx = i;
48610 return;
48611 }
48612 DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
48613 (long) i, (long) t));
48614 }
48615 i = (i + step) % n;
48616
48617 /* guaranteed to finish, as hash is never full */
48618 DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n));
48619 }
48620 }
48621#endif /* DUK_USE_HOBJECT_HASH_PART */
48622
48623 /* not found */
48624 *e_idx = -1;
48625 *h_idx = -1;
48626}
48627
48628/* For internal use: get non-accessor entry value */
48629DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) {
48630 duk_int_t e_idx;
48631 duk_int_t h_idx;
48632
48633 DUK_ASSERT(obj != NULL);
48634 DUK_ASSERT(key != NULL);
48635 DUK_UNREF(heap);
48636
48637 duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
48638 if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
48639 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
48640 } else {
48641 return NULL;
48642 }
48643}
48644
48645/* For internal use: get non-accessor entry value and attributes */
48646DUK_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) {
48647 duk_int_t e_idx;
48648 duk_int_t h_idx;
48649
48650 DUK_ASSERT(obj != NULL);
48651 DUK_ASSERT(key != NULL);
48652 DUK_ASSERT(out_attrs != NULL);
48653 DUK_UNREF(heap);
48654
48655 duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
48656 if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
48657 *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
48658 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
48659 } else {
48660 *out_attrs = 0;
48661 return NULL;
48662 }
48663}
48664
48665/* For internal use: get array part value */
48666DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) {
48667 duk_tval *tv;
48668
48669 DUK_ASSERT(obj != NULL);
48670 DUK_UNREF(heap);
48671
48672 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
48673 return NULL;
48674 }
48675 if (i >= DUK_HOBJECT_GET_ASIZE(obj)) {
48676 return NULL;
48677 }
48678 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i);
48679 return tv;
48680}
48681
48682/*
48683 * Allocate and initialize a new entry, resizing the properties allocation
48684 * if necessary. Returns entry index (e_idx) or throws an error if alloc fails.
48685 *
48686 * Sets the key of the entry (increasing the key's refcount), and updates
48687 * the hash part if it exists. Caller must set value and flags, and update
48688 * the entry value refcount. A decref for the previous value is not necessary.
48689 */
48690
48691DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
48692 duk_uint32_t idx;
48693
48694 DUK_ASSERT(thr != NULL);
48695 DUK_ASSERT(obj != NULL);
48696 DUK_ASSERT(key != NULL);
48697 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj));
48698
48699#ifdef DUK_USE_ASSERTIONS
48700 /* key must not already exist in entry part */
48701 {
48702 duk_uint_fast32_t i;
48703 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
48704 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key);
48705 }
48706 }
48707#endif
48708
48709 if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) {
48710 /* only need to guarantee 1 more slot, but allocation growth is in chunks */
48711 DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry"));
48712 duk__grow_props_for_new_entry_item(thr, obj);
48713 }
48714 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj));
48715 idx = DUK_HOBJECT_POSTINC_ENEXT(obj);
48716
48717 /* previous value is assumed to be garbage, so don't touch it */
48718 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key);
48719 DUK_HSTRING_INCREF(thr, key);
48720
48721#if defined(DUK_USE_HOBJECT_HASH_PART)
48722 if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) {
48723 duk_uint32_t n;
48724 duk_uint32_t i, step;
48725 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
48726
48727 n = DUK_HOBJECT_GET_HSIZE(obj);
48728 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
48729 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
48730
48731 for (;;) {
48732 duk_uint32_t t = h_base[i];
48733 if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
48734 DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() inserted key into hash part, %ld -> %ld",
48735 (long) i, (long) idx));
48736 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
48737 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
48738 DUK_ASSERT_DISABLE(idx >= 0);
48739 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
48740 h_base[i] = idx;
48741 break;
48742 }
48743 DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i));
48744 i = (i + step) % n;
48745
48746 /* guaranteed to find an empty slot */
48747 DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj)));
48748 }
48749 }
48750#endif /* DUK_USE_HOBJECT_HASH_PART */
48751
48752 /* Note: we could return the hash index here too, but it's not
48753 * needed right now.
48754 */
48755
48756 DUK_ASSERT_DISABLE(idx >= 0);
48757 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
48758 DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
48759 return idx;
48760}
48761
48762/*
48763 * Object internal value
48764 *
48765 * Returned value is guaranteed to be reachable / incref'd, caller does not need
48766 * to incref OR decref. No proxies or accessors are invoked, no prototype walk.
48767 */
48768
48769DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv_out) {
48770 duk_int_t e_idx;
48771 duk_int_t h_idx;
48772
48773 DUK_ASSERT(heap != NULL);
48774 DUK_ASSERT(obj != NULL);
48775 DUK_ASSERT(tv_out != NULL);
48776
48777 /* always in entry part, no need to look up parents etc */
48778 duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx);
48779 if (e_idx >= 0) {
48780 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx));
48781 DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx));
48782 return 1;
48783 }
48784 DUK_TVAL_SET_UNDEFINED(tv_out);
48785 return 0;
48786}
48787
48788DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) {
48789 duk_tval tv;
48790
48791 DUK_ASSERT(heap != NULL);
48792 DUK_ASSERT(obj != NULL);
48793
48794 /* This is not strictly necessary, but avoids compiler warnings; e.g.
48795 * gcc won't reliably detect that no uninitialized data is read below.
48796 */
48797 DUK_MEMZERO((void *) &tv, sizeof(duk_tval));
48798
48799 if (duk_hobject_get_internal_value(heap, obj, &tv)) {
48800 duk_hstring *h;
48801 DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
48802 h = DUK_TVAL_GET_STRING(&tv);
48803 return h;
48804 }
48805
48806 return NULL;
48807}
48808
48809/*
48810 * Arguments handling helpers (argument map mainly).
48811 *
48812 * An arguments object has exotic behavior for some numeric indices.
48813 * Accesses may translate to identifier operations which may have
48814 * arbitrary side effects (potentially invalidating any duk_tval
48815 * pointers).
48816 */
48817
48818/* Lookup 'key' from arguments internal 'map', perform a variable lookup
48819 * if mapped, and leave the result on top of stack (and return non-zero).
48820 * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]].
48821 */
48822DUK_LOCAL
48823duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
48824 duk_hobject *obj,
48825 duk_hstring *key,
48826 duk_propdesc *temp_desc,
48827 duk_hobject **out_map,
48828 duk_hobject **out_varenv) {
48829 duk_context *ctx = (duk_context *) thr;
48830 duk_hobject *map;
48831 duk_hobject *varenv;
48832 duk_bool_t rc;
48833
48834 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48835
48836 DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p "
48837 "(obj -> %!O, key -> %!O)",
48838 (void *) thr, (void *) obj, (void *) key, (void *) temp_desc,
48839 (duk_heaphdr *) obj, (duk_heaphdr *) key));
48840
48841 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
48842 DUK_DDD(DUK_DDDPRINT("-> no 'map'"));
48843 return 0;
48844 }
48845
48846 map = duk_require_hobject(ctx, -1);
48847 DUK_ASSERT(map != NULL);
48848 duk_pop(ctx); /* map is reachable through obj */
48849
48850 if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
48851 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
48852 return 0;
48853 }
48854
48855 /* [... varname] */
48856 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
48857 (duk_tval *) duk_get_tval(ctx, -1)));
48858 DUK_ASSERT(duk_is_string(ctx, -1)); /* guaranteed when building arguments */
48859
48860 /* get varenv for varname (callee's declarative lexical environment) */
48861 rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
48862 DUK_UNREF(rc);
48863 DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */
48864 varenv = duk_require_hobject(ctx, -1);
48865 DUK_ASSERT(varenv != NULL);
48866 duk_pop(ctx); /* varenv remains reachable through 'obj' */
48867
48868 DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
48869
48870 /* success: leave varname in stack */
48871 *out_map = map;
48872 *out_varenv = varenv;
48873 return 1; /* [... varname] */
48874}
48875
48876/* Lookup 'key' from arguments internal 'map', and leave replacement value
48877 * on stack top if mapped (and return non-zero).
48878 * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
48879 */
48880DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
48881 duk_context *ctx = (duk_context *) thr;
48882 duk_hobject *map;
48883 duk_hobject *varenv;
48884 duk_hstring *varname;
48885
48886 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48887
48888 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
48889 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior"));
48890 return 0;
48891 }
48892
48893 /* [... varname] */
48894
48895 varname = duk_require_hstring(ctx, -1);
48896 DUK_ASSERT(varname != NULL);
48897 duk_pop(ctx); /* varname is still reachable */
48898
48899 DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
48900 "key=%!O, varname=%!O",
48901 (duk_heaphdr *) key,
48902 (duk_heaphdr *) varname));
48903
48904 (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/);
48905
48906 /* [... value this_binding] */
48907
48908 duk_pop(ctx);
48909
48910 /* leave result on stack top */
48911 return 1;
48912}
48913
48914/* Lookup 'key' from arguments internal 'map', perform a variable write if mapped.
48915 * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]).
48916 * Assumes stack top contains 'put' value (which is NOT popped).
48917 */
48918DUK_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) {
48919 duk_context *ctx = (duk_context *) thr;
48920 duk_hobject *map;
48921 duk_hobject *varenv;
48922 duk_hstring *varname;
48923
48924 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48925
48926 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
48927 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior"));
48928 return;
48929 }
48930
48931 /* [... put_value varname] */
48932
48933 varname = duk_require_hstring(ctx, -1);
48934 DUK_ASSERT(varname != NULL);
48935 duk_pop(ctx); /* varname is still reachable */
48936
48937 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
48938 "key=%!O, varname=%!O, value=%!T",
48939 (duk_heaphdr *) key,
48940 (duk_heaphdr *) varname,
48941 (duk_tval *) duk_require_tval(ctx, -1)));
48942
48943 /* [... put_value] */
48944
48945 /*
48946 * Note: although arguments object variable mappings are only established
48947 * for non-strict functions (and a call to a non-strict function created
48948 * the arguments object in question), an inner strict function may be doing
48949 * the actual property write. Hence the throw_flag applied here comes from
48950 * the property write call.
48951 */
48952
48953 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, -1), throw_flag);
48954
48955 /* [... put_value] */
48956}
48957
48958/* Lookup 'key' from arguments internal 'map', delete mapping if found.
48959 * Used in E5 Section 10.6 algorithm for [[Delete]]. Note that the
48960 * variable/argument itself (where the map points) is not deleted.
48961 */
48962DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
48963 duk_context *ctx = (duk_context *) thr;
48964 duk_hobject *map;
48965
48966 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48967
48968 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
48969 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior"));
48970 return;
48971 }
48972
48973 map = duk_require_hobject(ctx, -1);
48974 DUK_ASSERT(map != NULL);
48975 duk_pop(ctx); /* map is reachable through obj */
48976
48977 DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
48978 (duk_heaphdr *) key));
48979
48980 /* Note: no recursion issue, we can trust 'map' to behave */
48981 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map));
48982 DUK_DDD(DUK_DDDPRINT("map before deletion: %!O", (duk_heaphdr *) map));
48983 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
48984 DUK_DDD(DUK_DDDPRINT("map after deletion: %!O", (duk_heaphdr *) map));
48985}
48986
48987/*
48988 * Ecmascript compliant [[GetOwnProperty]](P), for internal use only.
48989 *
48990 * If property is found:
48991 * - Fills descriptor fields to 'out_desc'
48992 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
48993 * property onto the stack ('undefined' for accessor properties).
48994 * - Returns non-zero
48995 *
48996 * If property is not found:
48997 * - 'out_desc' is left in untouched state (possibly garbage)
48998 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
48999 * set)
49000 * - Returns zero
49001 *
49002 * Notes:
49003 *
49004 * - Getting a property descriptor may cause an allocation (and hence
49005 * GC) to take place, hence reachability and refcount of all related
49006 * values matter. Reallocation of value stack, properties, etc may
49007 * invalidate many duk_tval pointers (concretely, those which reside
49008 * in memory areas subject to reallocation). However, heap object
49009 * pointers are never affected (heap objects have stable pointers).
49010 *
49011 * - The value of a plain property is always reachable and has a non-zero
49012 * reference count.
49013 *
49014 * - The value of a virtual property is not necessarily reachable from
49015 * elsewhere and may have a refcount of zero. Hence we push it onto
49016 * the valstack for the caller, which ensures it remains reachable
49017 * while it is needed.
49018 *
49019 * - There are no virtual accessor properties. Hence, all getters and
49020 * setters are always related to concretely stored properties, which
49021 * ensures that the get/set functions in the resulting descriptor are
49022 * reachable and have non-zero refcounts. Should there be virtual
49023 * accessor properties later, this would need to change.
49024 */
49025
49026DUK_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) {
49027 duk_context *ctx = (duk_context *) thr;
49028 duk_tval *tv;
49029
49030 DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
49031 "arr_idx=%ld (obj -> %!O, key -> %!O)",
49032 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
49033 (long) flags, (long) arr_idx,
49034 (duk_heaphdr *) obj, (duk_heaphdr *) key));
49035
49036 DUK_ASSERT(ctx != NULL);
49037 DUK_ASSERT(thr != NULL);
49038 DUK_ASSERT(thr->heap != NULL);
49039 DUK_ASSERT(obj != NULL);
49040 DUK_ASSERT(key != NULL);
49041 DUK_ASSERT(out_desc != NULL);
49042 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
49043
49044 /* XXX: optimize this filling behavior later */
49045 out_desc->flags = 0;
49046 out_desc->get = NULL;
49047 out_desc->set = NULL;
49048 out_desc->e_idx = -1;
49049 out_desc->h_idx = -1;
49050 out_desc->a_idx = -1;
49051
49052 /*
49053 * Array part
49054 */
49055
49056 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
49057 if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
49058 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
49059 if (!DUK_TVAL_IS_UNUSED(tv)) {
49060 DUK_DDD(DUK_DDDPRINT("-> found in array part"));
49061 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49062 duk_push_tval(ctx, tv);
49063 }
49064 /* implicit attributes */
49065 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
49066 DUK_PROPDESC_FLAG_CONFIGURABLE |
49067 DUK_PROPDESC_FLAG_ENUMERABLE;
49068 out_desc->a_idx = arr_idx;
49069 goto prop_found;
49070 }
49071 }
49072 /* assume array part is comprehensive (contains all array indexed elements
49073 * or none of them); hence no need to check the entries part here.
49074 */
49075 DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property (has array part, "
49076 "should be there if present)"));
49077 goto prop_not_found_concrete;
49078 }
49079
49080 /*
49081 * Entries part
49082 */
49083
49084 duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx);
49085 if (out_desc->e_idx >= 0) {
49086 duk_int_t e_idx = out_desc->e_idx;
49087 out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
49088 if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) {
49089 DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
49090 out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
49091 out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
49092 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49093 /* a dummy undefined value is pushed to make valstack
49094 * behavior uniform for caller
49095 */
49096 duk_push_undefined(ctx);
49097 }
49098 } else {
49099 DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
49100 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
49101 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49102 duk_push_tval(ctx, tv);
49103 }
49104 }
49105 goto prop_found;
49106 }
49107
49108 /*
49109 * Not found as a concrete property, check whether a String object
49110 * virtual property matches.
49111 */
49112
49113 prop_not_found_concrete:
49114
49115 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
49116 DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
49117 (duk_heaphdr *) key, (long) arr_idx));
49118
49119 if (arr_idx != DUK__NO_ARRAY_INDEX) {
49120 duk_hstring *h_val;
49121
49122 DUK_DDD(DUK_DDDPRINT("array index exists"));
49123
49124 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
49125 DUK_ASSERT(h_val);
49126 if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
49127 DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
49128 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49129 duk_push_hstring(ctx, h_val);
49130 duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
49131 }
49132 out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
49133 DUK_PROPDESC_FLAG_VIRTUAL;
49134
49135 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49136 return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
49137 } else {
49138 /* index is above internal string length -> property is fully normal */
49139 DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
49140 }
49141 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49142 duk_hstring *h_val;
49143
49144 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
49145
49146 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
49147 DUK_ASSERT(h_val != NULL);
49148 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49149 duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
49150 }
49151 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
49152
49153 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49154 return 1; /* cannot be arguments exotic */
49155 }
49156 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
49157 duk_hbufferobject *h_bufobj;
49158 duk_uint_t byte_off;
49159 duk_small_uint_t elem_size;
49160
49161 h_bufobj = (duk_hbufferobject *) obj;
49162 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
49163 DUK_DDD(DUK_DDDPRINT("bufferobject property get for key: %!O, arr_idx: %ld",
49164 (duk_heaphdr *) key, (long) arr_idx));
49165
49166 if (arr_idx != DUK__NO_ARRAY_INDEX) {
49167 DUK_DDD(DUK_DDDPRINT("array index exists"));
49168
49169 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
49170 * length downshift won't.
49171 */
49172 if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
49173 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
49174 elem_size = 1 << h_bufobj->shift;
49175 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49176 duk_uint8_t *data;
49177
49178 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
49179 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
49180 duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
49181 } else {
49182 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
49183 duk_push_uint(ctx, 0);
49184 }
49185 }
49186 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
49187 DUK_PROPDESC_FLAG_ENUMERABLE |
49188 DUK_PROPDESC_FLAG_VIRTUAL;
49189
49190 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49191 return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
49192 } else {
49193 /* index is above internal buffer length -> property is fully normal */
49194 DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
49195 }
49196 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49197 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
49198
49199 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49200 /* Length in elements: take into account shift, but
49201 * intentionally don't check the underlying buffer here.
49202 */
49203 duk_push_uint(ctx, h_bufobj->length >> h_bufobj->shift);
49204 }
49205 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49206
49207 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49208 return 1; /* cannot be arguments exotic */
49209 } else if (key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
49210 /* If neutered must return 0; length is zeroed during
49211 * neutering.
49212 */
49213 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49214 duk_push_uint(ctx, h_bufobj->length);
49215 }
49216 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49217 return 1; /* cannot be arguments exotic */
49218 } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
49219 /* If neutered must return 0; offset is zeroed during
49220 * neutering.
49221 */
49222 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49223 duk_push_uint(ctx, h_bufobj->offset);
49224 }
49225 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49226 return 1; /* cannot be arguments exotic */
49227 } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
49228 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49229 duk_push_uint(ctx, 1 << h_bufobj->shift);
49230 }
49231 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49232 return 1; /* cannot be arguments exotic */
49233 }
49234 } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj)) {
49235 DUK_DDD(DUK_DDDPRINT("duktape/c object exotic property get for key: %!O, arr_idx: %ld",
49236 (duk_heaphdr *) key, (long) arr_idx));
49237
49238 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49239 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
49240
49241 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
49242 duk_int16_t func_nargs = ((duk_hnativefunction *) obj)->nargs;
49243 duk_push_int(ctx, func_nargs == DUK_HNATIVEFUNCTION_NARGS_VARARGS ? 0 : func_nargs);
49244 }
49245 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* not enumerable */
49246
49247 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49248 return 1; /* cannot be arguments exotic */
49249 }
49250 }
49251
49252 /* Array properties have exotic behavior but they are concrete,
49253 * so no special handling here.
49254 *
49255 * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]]
49256 * is only relevant as a post-check implemented below; hence no
49257 * check here.
49258 */
49259
49260 /*
49261 * Not found as concrete or virtual
49262 */
49263
49264 DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
49265 return 0;
49266
49267 /*
49268 * Found
49269 *
49270 * Arguments object has exotic post-processing, see E5 Section 10.6,
49271 * description of [[GetOwnProperty]] variant for arguments.
49272 */
49273
49274 prop_found:
49275 DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
49276
49277 /* Notes:
49278 * - only numbered indices are relevant, so arr_idx fast reject is good
49279 * (this is valid unless there are more than 4**32-1 arguments).
49280 * - since variable lookup has no side effects, this can be skipped if
49281 * DUK_GETDESC_FLAG_PUSH_VALUE is not set.
49282 */
49283
49284 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
49285 arr_idx != DUK__NO_ARRAY_INDEX &&
49286 (flags & DUK_GETDESC_FLAG_PUSH_VALUE)) {
49287 duk_propdesc temp_desc;
49288
49289 /* Magically bound variable cannot be an accessor. However,
49290 * there may be an accessor property (or a plain property) in
49291 * place with magic behavior removed. This happens e.g. when
49292 * a magic property is redefined with defineProperty().
49293 * Cannot assert for "not accessor" here.
49294 */
49295
49296 /* replaces top of stack with new value if necessary */
49297 DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0);
49298
49299 if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
49300 DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
49301 (duk_tval *) duk_get_tval(ctx, -2),
49302 (duk_tval *) duk_get_tval(ctx, -1)));
49303 /* [... old_result result] -> [... result] */
49304 duk_remove(ctx, -2);
49305 }
49306 }
49307
49308 return 1;
49309}
49310
49311DUK_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) {
49312 DUK_ASSERT(thr != NULL);
49313 DUK_ASSERT(obj != NULL);
49314 DUK_ASSERT(key != NULL);
49315 DUK_ASSERT(out_desc != NULL);
49316 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
49317
49318 return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags);
49319}
49320
49321/*
49322 * Ecmascript compliant [[GetProperty]](P), for internal use only.
49323 *
49324 * If property is found:
49325 * - Fills descriptor fields to 'out_desc'
49326 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
49327 * property onto the stack ('undefined' for accessor properties).
49328 * - Returns non-zero
49329 *
49330 * If property is not found:
49331 * - 'out_desc' is left in untouched state (possibly garbage)
49332 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
49333 * set)
49334 * - Returns zero
49335 *
49336 * May cause arbitrary side effects and invalidate (most) duk_tval
49337 * pointers.
49338 */
49339
49340DUK_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) {
49341 duk_hobject *curr;
49342 duk_uint32_t arr_idx;
49343 duk_uint_t sanity;
49344
49345 DUK_ASSERT(thr != NULL);
49346 DUK_ASSERT(thr->heap != NULL);
49347 DUK_ASSERT(obj != NULL);
49348 DUK_ASSERT(key != NULL);
49349 DUK_ASSERT(out_desc != NULL);
49350 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
49351
49352 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
49353
49354 DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
49355 "arr_idx=%ld (obj -> %!O, key -> %!O)",
49356 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
49357 (long) flags, (long) arr_idx,
49358 (duk_heaphdr *) obj, (duk_heaphdr *) key));
49359
49360 curr = obj;
49361 DUK_ASSERT(curr != NULL);
49362 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
49363 do {
49364 if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
49365 /* stack contains value (if requested), 'out_desc' is set */
49366 return 1;
49367 }
49368
49369 /* not found in 'curr', next in prototype chain; impose max depth */
49370 if (sanity-- == 0) {
49371 if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) {
49372 /* treat like property not found */
49373 break;
49374 } else {
49375 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
49376 }
49377 }
49378 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
49379 } while (curr);
49380
49381 /* out_desc is left untouched (possibly garbage), caller must use return
49382 * value to determine whether out_desc can be looked up
49383 */
49384
49385 return 0;
49386}
49387
49388/*
49389 * Shallow fast path checks for accessing array elements with numeric
49390 * indices. The goal is to try to avoid coercing an array index to an
49391 * (interned) string for the most common lookups, in particular, for
49392 * standard Array objects.
49393 *
49394 * Interning is avoided but only for a very narrow set of cases:
49395 * - Object has array part, index is within array allocation, and
49396 * value is not unused (= key exists)
49397 * - Object has no interfering exotic behavior (e.g. arguments or
49398 * string object exotic behaviors interfere, array exotic
49399 * behavior does not).
49400 *
49401 * Current shortcoming: if key does not exist (even if it is within
49402 * the array allocation range) a slow path lookup with interning is
49403 * always required. This can probably be fixed so that there is a
49404 * quick fast path for non-existent elements as well, at least for
49405 * standard Array objects.
49406 */
49407
49408DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
49409 duk_tval *tv;
49410 duk_uint32_t idx;
49411
49412 DUK_UNREF(thr);
49413
49414 if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
49415 !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
49416 !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
49417 !DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
49418 !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
49419 /* Must have array part and no conflicting exotic behaviors.
49420 * Doesn't need to have array special behavior, e.g. Arguments
49421 * object has array part.
49422 */
49423 return NULL;
49424 }
49425
49426 /* Arrays never have other exotic behaviors. */
49427
49428 DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer "
49429 "behavior, object has array part)"));
49430
49431#if defined(DUK_USE_FASTINT)
49432 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49433 idx = duk__tval_fastint_to_arr_idx(tv_key);
49434 } else
49435#endif
49436 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49437 idx = duk__tval_number_to_arr_idx(tv_key);
49438 } else {
49439 DUK_DDD(DUK_DDDPRINT("key is not a number"));
49440 return NULL;
49441 }
49442
49443 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49444 * is 0xffffffffUL. We don't need to check for that explicitly
49445 * because 0xffffffffUL will never be inside object 'a_size'.
49446 */
49447
49448 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
49449 DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part"));
49450 return NULL;
49451 }
49452 DUK_ASSERT(idx != 0xffffffffUL);
49453 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49454
49455 /* XXX: for array instances we could take a shortcut here and assume
49456 * Array.prototype doesn't contain an array index property.
49457 */
49458
49459 DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part"));
49460 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
49461 if (!DUK_TVAL_IS_UNUSED(tv)) {
49462 DUK_DDD(DUK_DDDPRINT("-> fast path successful"));
49463 return tv;
49464 }
49465
49466 DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path"));
49467 return NULL;
49468}
49469
49470DUK_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) {
49471 duk_tval *tv;
49472 duk_uint32_t idx;
49473 duk_uint32_t old_len, new_len;
49474
49475 if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) &&
49476 DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
49477 DUK_HOBJECT_HAS_EXTENSIBLE(obj))) {
49478 return 0;
49479 }
49480 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */
49481
49482#if defined(DUK_USE_FASTINT)
49483 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49484 idx = duk__tval_fastint_to_arr_idx(tv_key);
49485 } else
49486#endif
49487 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49488 idx = duk__tval_number_to_arr_idx(tv_key);
49489 } else {
49490 DUK_DDD(DUK_DDDPRINT("key is not a number"));
49491 return 0;
49492 }
49493
49494 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49495 * is 0xffffffffUL. We don't need to check for that explicitly
49496 * because 0xffffffffUL will never be inside object 'a_size'.
49497 */
49498
49499 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { /* for resizing of array part, use slow path */
49500 return 0;
49501 }
49502 DUK_ASSERT(idx != 0xffffffffUL);
49503 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49504
49505 old_len = duk__get_old_array_length(thr, obj, temp_desc);
49506
49507 if (idx >= old_len) {
49508 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
49509 "(arr_idx=%ld, old_len=%ld)",
49510 (long) idx, (long) old_len));
49511 if (!(temp_desc->flags & DUK_PROPDESC_FLAG_WRITABLE)) {
49512 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
49513 return 0; /* not reachable */
49514 }
49515 new_len = idx + 1;
49516
49517 /* No resize has occurred so temp_desc->e_idx is still OK */
49518 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
49519 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
49520 DUK_TVAL_SET_FASTINT_U32(tv, new_len); /* no need for decref/incref because value is a number */
49521 } else {
49522 ;
49523 }
49524
49525 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
49526 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
49527
49528 DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx));
49529 return 1;
49530}
49531
49532/*
49533 * Fast path for bufferobject getprop/putprop
49534 */
49535
49536DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
49537 duk_context *ctx;
49538 duk_uint32_t idx;
49539 duk_hbufferobject *h_bufobj;
49540 duk_uint_t byte_off;
49541 duk_small_uint_t elem_size;
49542 duk_uint8_t *data;
49543
49544 ctx = (duk_context *) thr;
49545
49546 if (!DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
49547 return 0;
49548 }
49549 h_bufobj = (duk_hbufferobject *) obj;
49550
49551#if defined(DUK_USE_FASTINT)
49552 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49553 idx = duk__tval_fastint_to_arr_idx(tv_key);
49554 } else
49555#endif
49556 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49557 idx = duk__tval_number_to_arr_idx(tv_key);
49558 } else {
49559 return 0;
49560 }
49561
49562 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49563 * is 0xffffffffUL. We don't need to check for that explicitly
49564 * because 0xffffffffUL will never be inside bufferobject length.
49565 */
49566
49567 /* Careful with wrapping (left shifting idx would be unsafe). */
49568 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
49569 return 0;
49570 }
49571 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49572
49573 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
49574 elem_size = 1 << h_bufobj->shift;
49575
49576 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
49577 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
49578 duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
49579 } else {
49580 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
49581 duk_push_uint(ctx, 0);
49582 }
49583
49584 return 1;
49585}
49586
49587DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
49588 duk_context *ctx;
49589 duk_uint32_t idx;
49590 duk_hbufferobject *h_bufobj;
49591 duk_uint_t byte_off;
49592 duk_small_uint_t elem_size;
49593 duk_uint8_t *data;
49594
49595 ctx = (duk_context *) thr;
49596
49597 if (!(DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
49598 DUK_TVAL_IS_NUMBER(tv_val))) {
49599 return 0;
49600 }
49601 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufferobjects now */
49602
49603 h_bufobj = (duk_hbufferobject *) obj;
49604#if defined(DUK_USE_FASTINT)
49605 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49606 idx = duk__tval_fastint_to_arr_idx(tv_key);
49607 } else
49608#endif
49609 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49610 idx = duk__tval_number_to_arr_idx(tv_key);
49611 } else {
49612 return 0;
49613 }
49614
49615 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49616 * is 0xffffffffUL. We don't need to check for that explicitly
49617 * because 0xffffffffUL will never be inside bufferobject length.
49618 */
49619
49620 /* Careful with wrapping (left shifting idx would be unsafe). */
49621 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
49622 return 0;
49623 }
49624 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49625
49626 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
49627 elem_size = 1 << h_bufobj->shift;
49628
49629 /* Value is required to be a number in the fast path so there
49630 * are no side effects in write coercion.
49631 */
49632 duk_push_tval(ctx, tv_val);
49633 DUK_ASSERT(duk_is_number(ctx, -1));
49634
49635 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
49636 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
49637 duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
49638 } else {
49639 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
49640 }
49641
49642 duk_pop(ctx);
49643 return 1;
49644}
49645
49646/*
49647 * GETPROP: Ecmascript property read.
49648 */
49649
49650DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
49651 duk_context *ctx = (duk_context *) thr;
49652 duk_tval tv_obj_copy;
49653 duk_tval tv_key_copy;
49654 duk_hobject *curr = NULL;
49655 duk_hstring *key = NULL;
49656 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
49657 duk_propdesc desc;
49658 duk_uint_t sanity;
49659
49660 DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
49661 (void *) thr, (void *) tv_obj, (void *) tv_key,
49662 (duk_tval *) tv_obj, (duk_tval *) tv_key));
49663
49664 DUK_ASSERT(ctx != NULL);
49665 DUK_ASSERT(thr != NULL);
49666 DUK_ASSERT(thr->heap != NULL);
49667 DUK_ASSERT(tv_obj != NULL);
49668 DUK_ASSERT(tv_key != NULL);
49669
49670 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
49671
49672 /*
49673 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
49674 * them being invalidated by a valstack resize.
49675 *
49676 * XXX: this is now an overkill for many fast paths. Rework this
49677 * to be faster (although switching to a valstack discipline might
49678 * be a better solution overall).
49679 */
49680
49681 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
49682 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
49683 tv_obj = &tv_obj_copy;
49684 tv_key = &tv_key_copy;
49685
49686 /*
49687 * Coercion and fast path processing
49688 */
49689
49690 switch (DUK_TVAL_GET_TAG(tv_obj)) {
49691 case DUK_TAG_UNDEFINED:
49692 case DUK_TAG_NULL: {
49693 /* Note: unconditional throw */
49694 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
49695#if defined(DUK_USE_PARANOID_ERRORS)
49696 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
49697#else
49698 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
49699 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
49700#endif
49701 return 0;
49702 }
49703
49704 case DUK_TAG_BOOLEAN: {
49705 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
49706 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
49707 break;
49708 }
49709
49710 case DUK_TAG_STRING: {
49711 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
49712 duk_int_t pop_count;
49713
49714#if defined(DUK_USE_FASTINT)
49715 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49716 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
49717 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
49718 pop_count = 0;
49719 } else
49720#endif
49721 if (DUK_TVAL_IS_NUMBER(tv_key)) {
49722 arr_idx = duk__tval_number_to_arr_idx(tv_key);
49723 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
49724 pop_count = 0;
49725 } else {
49726 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49727 DUK_ASSERT(key != NULL);
49728 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
49729 "coercion key is %!T, arr_idx %ld",
49730 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49731 pop_count = 1;
49732 }
49733
49734 if (arr_idx != DUK__NO_ARRAY_INDEX &&
49735 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
49736 duk_pop_n(ctx, pop_count);
49737 duk_push_hstring(ctx, h);
49738 duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
49739
49740 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
49741 "after coercion -> return char)",
49742 (duk_tval *) duk_get_tval(ctx, -1)));
49743 return 1;
49744 }
49745
49746 if (pop_count == 0) {
49747 /* This is a pretty awkward control flow, but we need to recheck the
49748 * key coercion here.
49749 */
49750 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49751 DUK_ASSERT(key != NULL);
49752 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
49753 "coercion key is %!T, arr_idx %ld",
49754 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49755 }
49756
49757 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49758 duk_pop(ctx); /* [key] -> [] */
49759 duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
49760
49761 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
49762 "return string length)",
49763 (duk_tval *) duk_get_tval(ctx, -1)));
49764 return 1;
49765 }
49766 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
49767 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
49768 goto lookup; /* avoid double coercion */
49769 }
49770
49771 case DUK_TAG_OBJECT: {
49772 duk_tval *tmp;
49773
49774 curr = DUK_TVAL_GET_OBJECT(tv_obj);
49775 DUK_ASSERT(curr != NULL);
49776
49777 tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
49778 if (tmp) {
49779 duk_push_tval(ctx, tmp);
49780
49781 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
49782 "fast path)",
49783 (duk_tval *) duk_get_tval(ctx, -1)));
49784 return 1;
49785 }
49786
49787 if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) {
49788 /* Read value pushed on stack. */
49789 DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufferobject "
49790 "fast path)",
49791 (duk_tval *) duk_get_tval(ctx, -1)));
49792 return 1;
49793 }
49794
49795#if defined(DUK_USE_ES6_PROXY)
49796 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(curr))) {
49797 duk_hobject *h_target;
49798
49799 if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
49800 /* -> [ ... trap handler ] */
49801 DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
49802 duk_push_hobject(ctx, h_target); /* target */
49803 duk_push_tval(ctx, tv_key); /* P */
49804 duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
49805 duk_call_method(ctx, 3 /*nargs*/);
49806
49807 /* Target object must be checked for a conflicting
49808 * non-configurable property.
49809 */
49810 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49811 DUK_ASSERT(key != NULL);
49812
49813 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
49814 duk_tval *tv_hook = duk_require_tval(ctx, -3); /* value from hook */
49815 duk_tval *tv_targ = duk_require_tval(ctx, -1); /* value from target */
49816 duk_bool_t datadesc_reject;
49817 duk_bool_t accdesc_reject;
49818
49819 DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for "
49820 "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
49821 "desc.get=%p, desc.set=%p",
49822 (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ,
49823 (unsigned long) desc.flags,
49824 (void *) desc.get, (void *) desc.set));
49825
49826 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
49827 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
49828 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
49829 !duk_js_samevalue(tv_hook, tv_targ);
49830 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
49831 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
49832 (desc.get == NULL) &&
49833 !DUK_TVAL_IS_UNDEFINED(tv_hook);
49834 if (datadesc_reject || accdesc_reject) {
49835 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
49836 }
49837
49838 duk_pop_2(ctx);
49839 } else {
49840 duk_pop(ctx);
49841 }
49842 return 1; /* return value */
49843 }
49844
49845 curr = h_target; /* resume lookup from target */
49846 DUK_TVAL_SET_OBJECT(tv_obj, curr);
49847 }
49848#endif /* DUK_USE_ES6_PROXY */
49849
49850 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
49851 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49852 DUK_ASSERT(key != NULL);
49853
49854 if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
49855 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
49856 "key matches magically bound property -> skip standard "
49857 "Get with replacement value)",
49858 (duk_tval *) duk_get_tval(ctx, -1)));
49859
49860 /* no need for 'caller' post-check, because 'key' must be an array index */
49861
49862 duk_remove(ctx, -2); /* [key result] -> [result] */
49863 return 1;
49864 }
49865
49866 goto lookup; /* avoid double coercion */
49867 }
49868 break;
49869 }
49870
49871 /* Buffer has virtual properties similar to string, but indexed values
49872 * are numbers, not 1-byte buffers/strings which would perform badly.
49873 */
49874 case DUK_TAG_BUFFER: {
49875 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
49876 duk_int_t pop_count;
49877
49878 /*
49879 * Because buffer values are often looped over, a number fast path
49880 * is important.
49881 */
49882
49883#if defined(DUK_USE_FASTINT)
49884 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49885 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
49886 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
49887 pop_count = 0;
49888 }
49889 else
49890#endif
49891 if (DUK_TVAL_IS_NUMBER(tv_key)) {
49892 arr_idx = duk__tval_number_to_arr_idx(tv_key);
49893 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
49894 pop_count = 0;
49895 } else {
49896 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49897 DUK_ASSERT(key != NULL);
49898 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
49899 "coercion key is %!T, arr_idx %ld",
49900 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49901 pop_count = 1;
49902 }
49903
49904 if (arr_idx != DUK__NO_ARRAY_INDEX &&
49905 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
49906 duk_pop_n(ctx, pop_count);
49907 duk_push_uint(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
49908
49909 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
49910 "after coercion -> return byte as number)",
49911 (duk_tval *) duk_get_tval(ctx, -1)));
49912 return 1;
49913 }
49914
49915 if (pop_count == 0) {
49916 /* This is a pretty awkward control flow, but we need to recheck the
49917 * key coercion here.
49918 */
49919 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49920 DUK_ASSERT(key != NULL);
49921 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
49922 "coercion key is %!T, arr_idx %ld",
49923 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49924 }
49925
49926 if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
49927 key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
49928 duk_pop(ctx); /* [key] -> [] */
49929 duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
49930
49931 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' or 'byteLength' "
49932 "after coercion -> return buffer length)",
49933 (duk_tval *) duk_get_tval(ctx, -1)));
49934 return 1;
49935 } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
49936 duk_pop(ctx); /* [key] -> [] */
49937 duk_push_uint(ctx, 0); /* [] -> [res] */
49938
49939 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'byteOffset' after coercion -> "
49940 "return 0 for consistency with Buffer objects)",
49941 (duk_tval *) duk_get_tval(ctx, -1)));
49942 return 1;
49943 } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
49944 duk_pop(ctx); /* [key] -> [] */
49945 duk_push_uint(ctx, 1); /* [] -> [res] */
49946
49947 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'BYTES_PER_ELEMENT' after coercion -> "
49948 "return 1 for consistency with Buffer objects)",
49949 (duk_tval *) duk_get_tval(ctx, -1)));
49950 return 1;
49951 }
49952
49953 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
49954 curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
49955 goto lookup; /* avoid double coercion */
49956 }
49957
49958 case DUK_TAG_POINTER: {
49959 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
49960 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
49961 break;
49962 }
49963
49964 case DUK_TAG_LIGHTFUNC: {
49965 duk_int_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_obj);
49966
49967 /* Must coerce key: if key is an object, it may coerce to e.g. 'length'. */
49968 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49969
49970 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49971 duk_int_t lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
49972 duk_pop(ctx);
49973 duk_push_int(ctx, lf_len);
49974 return 1;
49975 } else if (key == DUK_HTHREAD_STRING_NAME(thr)) {
49976 duk_pop(ctx);
49977 duk_push_lightfunc_name(ctx, tv_obj);
49978 return 1;
49979 }
49980
49981 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
49982 curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
49983 goto lookup; /* avoid double coercion */
49984 }
49985
49986#if defined(DUK_USE_FASTINT)
49987 case DUK_TAG_FASTINT:
49988#endif
49989 default: {
49990 /* number */
49991 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
49992 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj));
49993 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
49994 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
49995 break;
49996 }
49997 }
49998
49999 /* key coercion (unless already coerced above) */
50000 DUK_ASSERT(key == NULL);
50001 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50002 DUK_ASSERT(key != NULL);
50003
50004 /*
50005 * Property lookup
50006 */
50007
50008 lookup:
50009 /* [key] (coerced) */
50010 DUK_ASSERT(curr != NULL);
50011 DUK_ASSERT(key != NULL);
50012
50013 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
50014 do {
50015 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
50016 goto next_in_chain;
50017 }
50018
50019 if (desc.get != NULL) {
50020 /* accessor with defined getter */
50021 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
50022
50023 duk_pop(ctx); /* [key undefined] -> [key] */
50024 duk_push_hobject(ctx, desc.get);
50025 duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
50026#ifdef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
50027 duk_dup(ctx, -3);
50028 duk_call_method(ctx, 1); /* [key getter this key] -> [key retval] */
50029#else
50030 duk_call_method(ctx, 0); /* [key getter this] -> [key retval] */
50031#endif
50032 } else {
50033 /* [key value] or [key undefined] */
50034
50035 /* data property or accessor without getter */
50036 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
50037 (desc.get == NULL));
50038
50039 /* if accessor without getter, return value is undefined */
50040 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
50041 duk_is_undefined(ctx, -1));
50042
50043 /* Note: for an accessor without getter, falling through to
50044 * check for "caller" exotic behavior is unnecessary as
50045 * "undefined" will never activate the behavior. But it does
50046 * no harm, so we'll do it anyway.
50047 */
50048 }
50049
50050 goto found; /* [key result] */
50051
50052 next_in_chain:
50053 /* XXX: option to pretend property doesn't exist if sanity limit is
50054 * hit might be useful.
50055 */
50056 if (sanity-- == 0) {
50057 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
50058 }
50059 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
50060 } while (curr);
50061
50062 /*
50063 * Not found
50064 */
50065
50066 duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */
50067
50068 DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1)));
50069 return 0;
50070
50071 /*
50072 * Found; post-processing (Function and arguments objects)
50073 */
50074
50075 found:
50076 /* [key result] */
50077
50078#if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
50079 /* Special behavior for 'caller' property of (non-bound) function objects
50080 * and non-strict Arguments objects: if 'caller' -value- (!) is a strict
50081 * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6).
50082 * Quite interestingly, a non-strict function with no formal arguments
50083 * will get an arguments object -without- special 'caller' behavior!
50084 *
50085 * The E5.1 spec is a bit ambiguous if this special behavior applies when
50086 * a bound function is the base value (not the 'caller' value): Section
50087 * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions
50088 * matches that of Section 15.3.5.4 ([[Get]] for Function instances).
50089 * However, Section 13.3.5.4 has "NOTE: Function objects created using
50090 * Function.prototype.bind use the default [[Get]] internal method."
50091 * The current implementation assumes this means that bound functions
50092 * should not have the special [[Get]] behavior.
50093 *
50094 * The E5.1 spec is also a bit unclear if the TypeError throwing is
50095 * applied if the 'caller' value is a strict bound function. The
50096 * current implementation will throw even for both strict non-bound
50097 * and strict bound functions.
50098 *
50099 * See test-dev-strict-func-as-caller-prop-value.js for quite extensive
50100 * tests.
50101 *
50102 * This exotic behavior is disabled when the non-standard 'caller' property
50103 * is enabled, as it conflicts with the free use of 'caller'.
50104 */
50105 if (key == DUK_HTHREAD_STRING_CALLER(thr) &&
50106 DUK_TVAL_IS_OBJECT(tv_obj)) {
50107 duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj);
50108 DUK_ASSERT(orig != NULL);
50109
50110 if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) ||
50111 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
50112 duk_hobject *h;
50113
50114 /* XXX: The TypeError is currently not applied to bound
50115 * functions because the 'strict' flag is not copied by
50116 * bind(). This may or may not be correct, the specification
50117 * only refers to the value being a "strict mode Function
50118 * object" which is ambiguous.
50119 */
50120 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(orig));
50121
50122 h = duk_get_hobject(ctx, -1); /* NULL if not an object */
50123 if (h &&
50124 DUK_HOBJECT_IS_FUNCTION(h) &&
50125 DUK_HOBJECT_HAS_STRICT(h)) {
50126 /* XXX: sufficient to check 'strict', assert for 'is function' */
50127 DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ);
50128 }
50129 }
50130 }
50131#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
50132
50133 duk_remove(ctx, -2); /* [key result] -> [result] */
50134
50135 DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(ctx, -1)));
50136 return 1;
50137}
50138
50139/*
50140 * HASPROP: Ecmascript property existence check ("in" operator).
50141 *
50142 * Interestingly, the 'in' operator does not do any coercion of
50143 * the target object.
50144 */
50145
50146DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
50147 duk_context *ctx = (duk_context *) thr;
50148 duk_tval tv_key_copy;
50149 duk_hobject *obj;
50150 duk_hstring *key;
50151 duk_uint32_t arr_idx;
50152 duk_bool_t rc;
50153 duk_propdesc desc;
50154
50155 DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
50156 (void *) thr, (void *) tv_obj, (void *) tv_key,
50157 (duk_tval *) tv_obj, (duk_tval *) tv_key));
50158
50159 DUK_ASSERT(thr != NULL);
50160 DUK_ASSERT(thr->heap != NULL);
50161 DUK_ASSERT(tv_obj != NULL);
50162 DUK_ASSERT(tv_key != NULL);
50163 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50164
50165 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
50166 tv_key = &tv_key_copy;
50167
50168 /*
50169 * The 'in' operator requires an object as its right hand side,
50170 * throwing a TypeError unconditionally if this is not the case.
50171 *
50172 * However, lightfuncs need to behave like fully fledged objects
50173 * here to be maximally transparent, so we need to handle them
50174 * here.
50175 */
50176
50177 /* XXX: Refactor key coercion so that it's only called once. It can't
50178 * be trivially lifted here because the object must be type checked
50179 * first.
50180 */
50181
50182 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
50183 obj = DUK_TVAL_GET_OBJECT(tv_obj);
50184 DUK_ASSERT(obj != NULL);
50185
50186 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50187 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
50188 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50189 if (duk__key_is_lightfunc_ownprop(thr, key)) {
50190 /* FOUND */
50191 rc = 1;
50192 goto pop_and_return;
50193 }
50194
50195 /* If not found, resume existence check from Function.prototype.
50196 * We can just substitute the value in this case; nothing will
50197 * need the original base value (as would be the case with e.g.
50198 * setters/getters.
50199 */
50200 obj = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
50201 } else {
50202 /* Note: unconditional throw */
50203 DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
50204 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
50205 }
50206
50207 /* XXX: fast path for arrays? */
50208
50209 DUK_ASSERT(key != NULL);
50210 DUK_ASSERT(obj != NULL);
50211 DUK_UNREF(arr_idx);
50212
50213#if defined(DUK_USE_ES6_PROXY)
50214 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
50215 duk_hobject *h_target;
50216 duk_bool_t tmp_bool;
50217
50218 /* XXX: the key in 'key in obj' is string coerced before we're called
50219 * (which is the required behavior in E5/E5.1/E6) so the key is a string
50220 * here already.
50221 */
50222
50223 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
50224 /* [ ... key trap handler ] */
50225 DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
50226 duk_push_hobject(ctx, h_target); /* target */
50227 duk_push_tval(ctx, tv_key); /* P */
50228 duk_call_method(ctx, 2 /*nargs*/);
50229 tmp_bool = duk_to_boolean(ctx, -1);
50230 if (!tmp_bool) {
50231 /* Target object must be checked for a conflicting
50232 * non-configurable property.
50233 */
50234
50235 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
50236 DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for "
50237 "conflicting property; desc.flags=0x%08lx, "
50238 "desc.get=%p, desc.set=%p",
50239 (duk_heaphdr *) key, (unsigned long) desc.flags,
50240 (void *) desc.get, (void *) desc.set));
50241 /* XXX: Extensibility check for target uses IsExtensible(). If we
50242 * implemented the isExtensible trap and didn't reject proxies as
50243 * proxy targets, it should be respected here.
50244 */
50245 if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */
50246 DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */
50247 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
50248 }
50249 }
50250 }
50251
50252 duk_pop_2(ctx); /* [ key trap_result ] -> [] */
50253 return tmp_bool;
50254 }
50255
50256 obj = h_target; /* resume check from proxy target */
50257 }
50258#endif /* DUK_USE_ES6_PROXY */
50259
50260 /* XXX: inline into a prototype walking loop? */
50261
50262 rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/); /* don't push value */
50263 /* fall through */
50264
50265 pop_and_return:
50266 duk_pop(ctx); /* [ key ] -> [] */
50267 return rc;
50268}
50269
50270/*
50271 * HASPROP variant used internally.
50272 *
50273 * This primitive must never throw an error, callers rely on this.
50274 * In particular, don't throw an error for prototype loops; instead,
50275 * pretend like the property doesn't exist if a prototype sanity limit
50276 * is reached.
50277 *
50278 * Does not implement proxy behavior: if applied to a proxy object,
50279 * returns key existence on the proxy object itself.
50280 */
50281
50282DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
50283 duk_propdesc dummy;
50284
50285 DUK_ASSERT(thr != NULL);
50286 DUK_ASSERT(thr->heap != NULL);
50287 DUK_ASSERT(obj != NULL);
50288 DUK_ASSERT(key != NULL);
50289
50290 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50291
50292 return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP); /* don't push value */
50293}
50294
50295/*
50296 * Helper: handle Array object 'length' write which automatically
50297 * deletes properties, see E5 Section 15.4.5.1, step 3. This is
50298 * quite tricky to get right.
50299 *
50300 * Used by duk_hobject_putprop().
50301 */
50302
50303DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc) {
50304 duk_bool_t rc;
50305 duk_tval *tv;
50306 duk_uint32_t res;
50307
50308 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50309
50310 /* This function is only called for objects with array exotic behavior.
50311 * The [[DefineOwnProperty]] algorithm for arrays requires that
50312 * 'length' can never have a value outside the unsigned 32-bit range,
50313 * attempt to write such a value is a RangeError. Here we can thus
50314 * assert for this. When Duktape internals go around the official
50315 * property write interface (doesn't happen often) this assumption is
50316 * easy to accidentally break, so such code must be written carefully.
50317 * See test-bi-array-push-maxlen.js.
50318 */
50319
50320 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 */
50321 DUK_UNREF(rc);
50322 DUK_ASSERT(rc != 0); /* arrays MUST have a 'length' property */
50323 DUK_ASSERT(temp_desc->e_idx >= 0);
50324
50325 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
50326 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* array 'length' is always a number, as we coerce it */
50327 DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) >= 0.0);
50328 DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (double) 0xffffffffUL);
50329 DUK_ASSERT((duk_double_t) (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv) == DUK_TVAL_GET_NUMBER(tv));
50330#if defined(DUK_USE_FASTINT)
50331 /* Downgrade checks are not made everywhere, so 'length' is not always
50332 * a fastint (it is a number though). This can be removed once length
50333 * is always guaranteed to be a fastint.
50334 */
50335 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv) || DUK_TVAL_IS_DOUBLE(tv));
50336 if (DUK_TVAL_IS_FASTINT(tv)) {
50337 res = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv);
50338 } else {
50339 res = (duk_uint32_t) DUK_TVAL_GET_DOUBLE(tv);
50340 }
50341#else
50342 res = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
50343#endif /* DUK_USE_FASTINT */
50344
50345 return res;
50346}
50347
50348DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr) {
50349 duk_context *ctx = (duk_context *) thr;
50350 duk_uint32_t res;
50351 duk_double_t d;
50352
50353 /* Input value should be on stack top and will be coerced and
50354 * popped. Refuse to update an Array's 'length' to a value
50355 * outside the 32-bit range. Negative zero is accepted as zero.
50356 */
50357
50358 /* XXX: fastint */
50359
50360 d = duk_to_number(ctx, -1);
50361 res = (duk_uint32_t) d;
50362 if ((duk_double_t) res != d) {
50363 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
50364 }
50365 duk_pop(ctx);
50366 return res;
50367}
50368
50369/* Delete elements required by a smaller length, taking into account
50370 * potentially non-configurable elements. Returns non-zero if all
50371 * elements could be deleted, and zero if all or some elements could
50372 * not be deleted. Also writes final "target length" to 'out_result_len'.
50373 * This is the length value that should go into the 'length' property
50374 * (must be set by the caller). Never throws an error.
50375 */
50376DUK_LOCAL
50377duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
50378 duk_hobject *obj,
50379 duk_uint32_t old_len,
50380 duk_uint32_t new_len,
50381 duk_bool_t force_flag,
50382 duk_uint32_t *out_result_len) {
50383 duk_uint32_t target_len;
50384 duk_uint_fast32_t i;
50385 duk_uint32_t arr_idx;
50386 duk_hstring *key;
50387 duk_tval *tv;
50388 duk_bool_t rc;
50389
50390 DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), "
50391 "probably need to remove elements",
50392 (long) old_len, (long) new_len));
50393
50394 /*
50395 * New length is smaller than old length, need to delete properties above
50396 * the new length.
50397 *
50398 * If array part exists, this is straightforward: array entries cannot
50399 * be non-configurable so this is guaranteed to work.
50400 *
50401 * If array part does not exist, array-indexed values are scattered
50402 * in the entry part, and some may not be configurable (preventing length
50403 * from becoming lower than their index + 1). To handle the algorithm
50404 * in E5 Section 15.4.5.1, step l correctly, we scan the entire property
50405 * set twice.
50406 */
50407
50408 DUK_ASSERT(thr != NULL);
50409 DUK_ASSERT(obj != NULL);
50410 DUK_ASSERT(new_len < old_len);
50411 DUK_ASSERT(out_result_len != NULL);
50412 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50413
50414 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
50415 /*
50416 * All defined array-indexed properties are in the array part
50417 * (we assume the array part is comprehensive), and all array
50418 * entries are writable, configurable, and enumerable. Thus,
50419 * nothing can prevent array entries from being deleted.
50420 */
50421
50422 DUK_DDD(DUK_DDDPRINT("have array part, easy case"));
50423
50424 if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) {
50425 /* XXX: assertion that entries >= old_len are already unused */
50426 i = old_len;
50427 } else {
50428 i = DUK_HOBJECT_GET_ASIZE(obj);
50429 }
50430 DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj));
50431
50432 while (i > new_len) {
50433 i--;
50434 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
50435 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
50436 }
50437
50438 *out_result_len = new_len;
50439 return 1;
50440 } else {
50441 /*
50442 * Entries part is a bit more complex
50443 */
50444
50445 /* Stage 1: find highest preventing non-configurable entry (if any).
50446 * When forcing, ignore non-configurability.
50447 */
50448
50449 DUK_DDD(DUK_DDDPRINT("no array part, slow case"));
50450
50451 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len "
50452 "(highest preventing non-configurable entry (if any))"));
50453
50454 target_len = new_len;
50455 if (force_flag) {
50456 DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1"));
50457 goto skip_stage1;
50458 }
50459 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
50460 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
50461 if (!key) {
50462 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
50463 continue;
50464 }
50465 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
50466 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
50467 continue;
50468 }
50469
50470 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
50471 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
50472 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
50473 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
50474
50475 if (arr_idx < new_len) {
50476 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len",
50477 (long) i, (long) arr_idx));
50478 continue;
50479 }
50480 if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) {
50481 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable",
50482 (long) i, (long) arr_idx));
50483 continue;
50484 }
50485
50486 /* relevant array index is non-configurable, blocks write */
50487 if (arr_idx >= target_len) {
50488 DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, "
50489 "update target_len %ld -> %ld",
50490 (long) i, (long) arr_idx, (long) target_len,
50491 (long) (arr_idx + 1)));
50492 target_len = arr_idx + 1;
50493 }
50494 }
50495 skip_stage1:
50496
50497 /* stage 2: delete configurable entries above target length */
50498
50499 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld",
50500 (long) old_len, (long) new_len, (long) target_len));
50501
50502 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove "
50503 "entries >= target_len"));
50504
50505 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
50506 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
50507 if (!key) {
50508 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
50509 continue;
50510 }
50511 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
50512 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
50513 continue;
50514 }
50515
50516 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
50517 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
50518 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
50519 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
50520
50521 if (arr_idx < target_len) {
50522 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len",
50523 (long) i, (long) arr_idx));
50524 continue;
50525 }
50526 DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)); /* stage 1 guarantees */
50527
50528 DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld",
50529 (long) i, (long) arr_idx));
50530
50531 /*
50532 * Slow delete, but we don't care as we're already in a very slow path.
50533 * The delete always succeeds: key has no exotic behavior, property
50534 * is configurable, and no resize occurs.
50535 */
50536 rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0);
50537 DUK_UNREF(rc);
50538 DUK_ASSERT(rc != 0);
50539 }
50540
50541 /* stage 3: update length (done by caller), decide return code */
50542
50543 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)"));
50544
50545 *out_result_len = target_len;
50546
50547 if (target_len == new_len) {
50548 DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success"));
50549 return 1;
50550 }
50551 DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented "
50552 "full length adjustment), return error"));
50553 return 0;
50554 }
50555
50556 DUK_UNREACHABLE();
50557}
50558
50559/* XXX: is valstack top best place for argument? */
50560DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
50561 duk_context *ctx = (duk_context *) thr;
50562 duk_propdesc desc;
50563 duk_uint32_t old_len;
50564 duk_uint32_t new_len;
50565 duk_uint32_t result_len;
50566 duk_tval *tv;
50567 duk_bool_t rc;
50568
50569 DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
50570 "new val: %!T",
50571 (duk_tval *) duk_get_tval(ctx, -1)));
50572
50573 DUK_ASSERT(thr != NULL);
50574 DUK_ASSERT(ctx != NULL);
50575 DUK_ASSERT(obj != NULL);
50576
50577 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50578
50579 DUK_ASSERT(duk_is_valid_index(ctx, -1));
50580
50581 /*
50582 * Get old and new length
50583 */
50584
50585 old_len = duk__get_old_array_length(thr, obj, &desc);
50586 duk_dup(ctx, -1); /* [in_val in_val] */
50587 new_len = duk__to_new_array_length_checked(thr); /* -> [in_val] */
50588 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
50589
50590 /*
50591 * Writability check
50592 */
50593
50594 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
50595 DUK_DDD(DUK_DDDPRINT("length is not writable, fail"));
50596 return 0;
50597 }
50598
50599 /*
50600 * New length not lower than old length => no changes needed
50601 * (not even array allocation).
50602 */
50603
50604 if (new_len >= old_len) {
50605 DUK_DDD(DUK_DDDPRINT("new length is higher than old length, just update length, no deletions"));
50606
50607 DUK_ASSERT(desc.e_idx >= 0);
50608 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
50609 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
50610 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50611 /* no decref needed for a number */
50612 DUK_TVAL_SET_FASTINT_U32(tv, new_len);
50613 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50614 return 1;
50615 }
50616
50617 DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries"));
50618
50619 /*
50620 * New length lower than old length => delete elements, then
50621 * update length.
50622 *
50623 * Note: even though a bunch of elements have been deleted, the 'desc' is
50624 * still valid as properties haven't been resized (and entries compacted).
50625 */
50626
50627 rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len);
50628 DUK_ASSERT(result_len >= new_len && result_len <= old_len);
50629
50630 DUK_ASSERT(desc.e_idx >= 0);
50631 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
50632 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
50633 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50634 /* no decref needed for a number */
50635 DUK_TVAL_SET_FASTINT_U32(tv, result_len);
50636 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50637
50638 /* XXX: shrink array allocation or entries compaction here? */
50639
50640 return rc;
50641}
50642
50643/*
50644 * PUTPROP: Ecmascript property write.
50645 *
50646 * Unlike Ecmascript primitive which returns nothing, returns 1 to indicate
50647 * success and 0 to indicate failure (assuming throw is not set).
50648 *
50649 * This is an extremely tricky function. Some examples:
50650 *
50651 * * Currently a decref may trigger a GC, which may compact an object's
50652 * property allocation. Consequently, any entry indices (e_idx) will
50653 * be potentially invalidated by a decref.
50654 *
50655 * * Exotic behaviors (strings, arrays, arguments object) require,
50656 * among other things:
50657 *
50658 * - Preprocessing before and postprocessing after an actual property
50659 * write. For example, array index write requires pre-checking the
50660 * array 'length' property for access control, and may require an
50661 * array 'length' update after the actual write has succeeded (but
50662 * not if it fails).
50663 *
50664 * - Deletion of multiple entries, as a result of array 'length' write.
50665 *
50666 * * Input values are taken as pointers which may point to the valstack.
50667 * If valstack is resized because of the put (this may happen at least
50668 * when the array part is abandoned), the pointers can be invalidated.
50669 * (We currently make a copy of all of the input values to avoid issues.)
50670 */
50671
50672DUK_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) {
50673 duk_context *ctx = (duk_context *) thr;
50674 duk_tval tv_obj_copy;
50675 duk_tval tv_key_copy;
50676 duk_tval tv_val_copy;
50677 duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */
50678 duk_hobject *curr;
50679 duk_hstring *key = NULL;
50680 duk_propdesc desc;
50681 duk_tval *tv;
50682 duk_uint32_t arr_idx;
50683 duk_bool_t rc;
50684 duk_int_t e_idx;
50685 duk_uint_t sanity;
50686 duk_uint32_t new_array_length = 0; /* 0 = no update */
50687
50688 DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld "
50689 "(obj -> %!T, key -> %!T, val -> %!T)",
50690 (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val,
50691 (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val));
50692
50693 DUK_ASSERT(thr != NULL);
50694 DUK_ASSERT(thr->heap != NULL);
50695 DUK_ASSERT(ctx != NULL);
50696 DUK_ASSERT(tv_obj != NULL);
50697 DUK_ASSERT(tv_key != NULL);
50698 DUK_ASSERT(tv_val != NULL);
50699
50700 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50701
50702 /*
50703 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
50704 * them being invalidated by a valstack resize.
50705 *
50706 * XXX: this is an overkill for some paths, so optimize this later
50707 * (or maybe switch to a stack arguments model entirely).
50708 */
50709
50710 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
50711 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
50712 DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
50713 tv_obj = &tv_obj_copy;
50714 tv_key = &tv_key_copy;
50715 tv_val = &tv_val_copy;
50716
50717 /*
50718 * Coercion and fast path processing.
50719 */
50720
50721 switch (DUK_TVAL_GET_TAG(tv_obj)) {
50722 case DUK_TAG_UNDEFINED:
50723 case DUK_TAG_NULL: {
50724 /* Note: unconditional throw */
50725 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)",
50726 (duk_tval *) tv_obj));
50727#if defined(DUK_USE_PARANOID_ERRORS)
50728 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
50729#else
50730 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
50731 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
50732#endif
50733 return 0;
50734 }
50735
50736 case DUK_TAG_BOOLEAN: {
50737 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
50738 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
50739 break;
50740 }
50741
50742 case DUK_TAG_STRING: {
50743 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
50744
50745 /*
50746 * Note: currently no fast path for array index writes.
50747 * They won't be possible anyway as strings are immutable.
50748 */
50749
50750 DUK_ASSERT(key == NULL);
50751 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50752 DUK_ASSERT(key != NULL);
50753
50754 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
50755 goto fail_not_writable;
50756 }
50757
50758 if (arr_idx != DUK__NO_ARRAY_INDEX &&
50759 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
50760 goto fail_not_writable;
50761 }
50762
50763 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
50764 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
50765 goto lookup; /* avoid double coercion */
50766 }
50767
50768 case DUK_TAG_OBJECT: {
50769 orig = DUK_TVAL_GET_OBJECT(tv_obj);
50770 DUK_ASSERT(orig != NULL);
50771
50772#if defined(DUK_USE_ROM_OBJECTS)
50773 /* With this check in place fast paths won't need read-only
50774 * object checks. This is technically incorrect if there are
50775 * setters that cause no writes to ROM objects, but current
50776 * built-ins don't have such setters.
50777 */
50778 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
50779 DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object"));
50780 goto fail_not_writable_no_pop; /* Must avoid duk_pop() in exit path */
50781 }
50782#endif
50783
50784 /* The fast path for array property put is not fully compliant:
50785 * If one places conflicting number-indexed properties into
50786 * Array.prototype (for example, a non-writable Array.prototype[7])
50787 * the fast path will incorrectly ignore them.
50788 *
50789 * This fast path could be made compliant by falling through
50790 * to the slow path if the previous value was UNUSED. This would
50791 * also remove the need to check for extensibility. Right now a
50792 * non-extensible array is slower than an extensible one as far
50793 * as writes are concerned.
50794 *
50795 * The fast path behavior is documented in more detail here:
50796 * tests/ecmascript/test-misc-array-fast-write.js
50797 */
50798
50799 if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val, &desc) != 0) {
50800 DUK_DDD(DUK_DDDPRINT("array fast path success"));
50801 return 1;
50802 }
50803
50804 if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
50805 DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufferobject fast path"));
50806 return 1;
50807 }
50808
50809#if defined(DUK_USE_ES6_PROXY)
50810 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(orig))) {
50811 duk_hobject *h_target;
50812 duk_bool_t tmp_bool;
50813
50814 if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
50815 /* -> [ ... trap handler ] */
50816 DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
50817 duk_push_hobject(ctx, h_target); /* target */
50818 duk_push_tval(ctx, tv_key); /* P */
50819 duk_push_tval(ctx, tv_val); /* V */
50820 duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
50821 duk_call_method(ctx, 4 /*nargs*/);
50822 tmp_bool = duk_to_boolean(ctx, -1);
50823 duk_pop(ctx);
50824 if (!tmp_bool) {
50825 goto fail_proxy_rejected;
50826 }
50827
50828 /* Target object must be checked for a conflicting
50829 * non-configurable property.
50830 */
50831 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50832 DUK_ASSERT(key != NULL);
50833
50834 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
50835 duk_tval *tv_targ = duk_require_tval(ctx, -1);
50836 duk_bool_t datadesc_reject;
50837 duk_bool_t accdesc_reject;
50838
50839 DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for "
50840 "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
50841 "desc.get=%p, desc.set=%p",
50842 (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ,
50843 (unsigned long) desc.flags,
50844 (void *) desc.get, (void *) desc.set));
50845
50846 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
50847 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
50848 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
50849 !duk_js_samevalue(tv_val, tv_targ);
50850 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
50851 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
50852 (desc.set == NULL);
50853 if (datadesc_reject || accdesc_reject) {
50854 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
50855 }
50856
50857 duk_pop_2(ctx);
50858 } else {
50859 duk_pop(ctx);
50860 }
50861 return 1; /* success */
50862 }
50863
50864 orig = h_target; /* resume write to target */
50865 DUK_TVAL_SET_OBJECT(tv_obj, orig);
50866 }
50867#endif /* DUK_USE_ES6_PROXY */
50868
50869 curr = orig;
50870 break;
50871 }
50872
50873 case DUK_TAG_BUFFER: {
50874 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
50875 duk_int_t pop_count = 0;
50876
50877 /*
50878 * Because buffer values may be looped over and read/written
50879 * from, an array index fast path is important.
50880 */
50881
50882#if defined(DUK_USE_FASTINT)
50883 if (DUK_TVAL_IS_FASTINT(tv_key)) {
50884 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
50885 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
50886 pop_count = 0;
50887 } else
50888#endif
50889 if (DUK_TVAL_IS_NUMBER(tv_key)) {
50890 arr_idx = duk__tval_number_to_arr_idx(tv_key);
50891 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
50892 pop_count = 0;
50893 } else {
50894 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50895 DUK_ASSERT(key != NULL);
50896 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
50897 "coercion key is %!T, arr_idx %ld",
50898 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
50899 pop_count = 1;
50900 }
50901
50902 if (arr_idx != DUK__NO_ARRAY_INDEX &&
50903 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
50904 duk_uint8_t *data;
50905 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
50906 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
50907
50908 /* XXX: duk_to_int() ensures we'll get 8 lowest bits as
50909 * as input is within duk_int_t range (capped outside it).
50910 */
50911#if defined(DUK_USE_FASTINT)
50912 /* Buffer writes are often integers. */
50913 if (DUK_TVAL_IS_FASTINT(tv_val)) {
50914 data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val);
50915 }
50916 else
50917#endif
50918 {
50919 duk_push_tval(ctx, tv_val);
50920 data[arr_idx] = (duk_uint8_t) duk_to_uint32(ctx, -1);
50921 pop_count++;
50922 }
50923
50924 duk_pop_n(ctx, pop_count);
50925 DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
50926 return 1;
50927 }
50928
50929 if (pop_count == 0) {
50930 /* This is a pretty awkward control flow, but we need to recheck the
50931 * key coercion here.
50932 */
50933 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50934 DUK_ASSERT(key != NULL);
50935 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
50936 "coercion key is %!T, arr_idx %ld",
50937 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
50938 }
50939
50940 if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
50941 key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr) ||
50942 key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr) ||
50943 key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
50944 goto fail_not_writable;
50945 }
50946
50947 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
50948 curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
50949 goto lookup; /* avoid double coercion */
50950 }
50951
50952 case DUK_TAG_POINTER: {
50953 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
50954 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
50955 break;
50956 }
50957
50958 case DUK_TAG_LIGHTFUNC: {
50959 /* All lightfunc own properties are non-writable and the lightfunc
50960 * is considered non-extensible. However, the write may be captured
50961 * by an inherited setter which means we can't stop the lookup here.
50962 */
50963
50964 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50965
50966 if (duk__key_is_lightfunc_ownprop(thr, key)) {
50967 goto fail_not_writable;
50968 }
50969
50970 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
50971 curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
50972 goto lookup; /* avoid double coercion */
50973 }
50974
50975#if defined(DUK_USE_FASTINT)
50976 case DUK_TAG_FASTINT:
50977#endif
50978 default: {
50979 /* number */
50980 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
50981 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
50982 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
50983 break;
50984 }
50985 }
50986
50987 DUK_ASSERT(key == NULL);
50988 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50989 DUK_ASSERT(key != NULL);
50990
50991 lookup:
50992
50993 /*
50994 * Check whether the property already exists in the prototype chain.
50995 * Note that the actual write goes into the original base object
50996 * (except if an accessor property captures the write).
50997 */
50998
50999 /* [key] */
51000
51001 DUK_ASSERT(curr != NULL);
51002 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
51003 do {
51004 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
51005 goto next_in_chain;
51006 }
51007
51008 if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
51009 /*
51010 * Found existing accessor property (own or inherited).
51011 * Call setter with 'this' set to orig, and value as the only argument.
51012 * Setter calls are OK even for ROM objects.
51013 *
51014 * Note: no exotic arguments object behavior, because [[Put]] never
51015 * calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b).
51016 */
51017
51018 duk_hobject *setter;
51019
51020 DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter"));
51021
51022 setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx);
51023 if (!setter) {
51024 goto fail_no_setter;
51025 }
51026 duk_push_hobject(ctx, setter);
51027 duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
51028 duk_push_tval(ctx, tv_val); /* [key setter this val] */
51029#ifdef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
51030 duk_dup(ctx, -4);
51031 duk_call_method(ctx, 2); /* [key setter this val key] -> [key retval] */
51032#else
51033 duk_call_method(ctx, 1); /* [key setter this val] -> [key retval] */
51034#endif
51035 duk_pop(ctx); /* ignore retval -> [key] */
51036 goto success_no_arguments_exotic;
51037 }
51038
51039 if (orig == NULL) {
51040 /*
51041 * Found existing own or inherited plain property, but original
51042 * base is a primitive value.
51043 */
51044 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
51045 goto fail_base_primitive;
51046 }
51047
51048 if (curr != orig) {
51049 /*
51050 * Found existing inherited plain property.
51051 * Do an access control check, and if OK, write
51052 * new property to 'orig'.
51053 */
51054 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
51055 DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible"));
51056 goto fail_not_extensible;
51057 }
51058 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
51059 DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable"));
51060 goto fail_not_writable;
51061 }
51062 DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable"));
51063 goto create_new;
51064 } else {
51065 /*
51066 * Found existing own (non-inherited) plain property.
51067 * Do an access control check and update in place.
51068 */
51069
51070 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
51071 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable"));
51072 goto fail_not_writable;
51073 }
51074 if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
51075 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable"));
51076 if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
51077 duk_hbufferobject *h_bufobj;
51078 duk_uint_t byte_off;
51079 duk_small_uint_t elem_size;
51080
51081 h_bufobj = (duk_hbufferobject *) curr;
51082 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
51083
51084 DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object"));
51085
51086 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
51087 * length downshift won't.
51088 */
51089 if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
51090 duk_uint8_t *data;
51091 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
51092
51093 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */
51094 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
51095 elem_size = 1 << h_bufobj->shift;
51096
51097 /* Coerce to number before validating pointers etc so that the
51098 * number coercions in duk_hbufferobject_validated_write() are
51099 * guaranteed to be side effect free and not invalidate the
51100 * pointer checks we do here.
51101 */
51102 duk_push_tval(ctx, tv_val);
51103 duk_to_number(ctx, -1);
51104
51105 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
51106 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
51107 duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
51108 } else {
51109 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
51110 }
51111 duk_pop(ctx);
51112 goto success_no_arguments_exotic;
51113 }
51114 }
51115
51116 goto fail_internal; /* should not happen */
51117 }
51118 DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable"));
51119 goto update_old;
51120 }
51121 DUK_UNREACHABLE();
51122
51123 next_in_chain:
51124 /* XXX: option to pretend property doesn't exist if sanity limit is
51125 * hit might be useful.
51126 */
51127 if (sanity-- == 0) {
51128 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
51129 }
51130 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
51131 } while (curr);
51132
51133 /*
51134 * Property not found in prototype chain.
51135 */
51136
51137 DUK_DDD(DUK_DDDPRINT("property not found in prototype chain"));
51138
51139 if (orig == NULL) {
51140 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
51141 goto fail_base_primitive;
51142 }
51143
51144 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
51145 DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible"));
51146 goto fail_not_extensible;
51147 }
51148
51149 goto create_new;
51150
51151 update_old:
51152
51153 /*
51154 * Update an existing property of the base object.
51155 */
51156
51157 /* [key] */
51158
51159 DUK_DDD(DUK_DDDPRINT("update an existing property of the original object"));
51160
51161 DUK_ASSERT(orig != NULL);
51162#if defined(DUK_USE_ROM_OBJECTS)
51163 /* This should not happen because DUK_TAG_OBJECT case checks
51164 * for this already, but check just in case.
51165 */
51166 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
51167 goto fail_not_writable;
51168 }
51169#endif
51170
51171 /* Although there are writable virtual properties (e.g. plain buffer
51172 * and buffer object number indices), they are handled before we come
51173 * here.
51174 */
51175 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
51176 DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
51177
51178 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
51179 key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51180 /*
51181 * Write to 'length' of an array is a very complex case
51182 * handled in a helper which updates both the array elements
51183 * and writes the new 'length'. The write may result in an
51184 * unconditional RangeError or a partial write (indicated
51185 * by a return code).
51186 *
51187 * Note: the helper has an unnecessary writability check
51188 * for 'length', we already know it is writable.
51189 */
51190
51191 DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
51192
51193 /* XXX: the helper currently assumes stack top contains new
51194 * 'length' value and the whole calling convention is not very
51195 * compatible with what we need.
51196 */
51197
51198 duk_push_tval(ctx, tv_val); /* [key val] */
51199 rc = duk__handle_put_array_length(thr, orig);
51200 duk_pop(ctx); /* [key val] -> [key] */
51201 if (!rc) {
51202 goto fail_array_length_partial;
51203 }
51204
51205 /* key is 'length', cannot match argument exotic behavior */
51206 goto success_no_arguments_exotic;
51207 }
51208
51209 if (desc.e_idx >= 0) {
51210 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
51211 DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv));
51212 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
51213 /* don't touch property attributes or hash part */
51214 DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT",
51215 (long) desc.e_idx, (duk_tval *) tv));
51216 } else {
51217 /* Note: array entries are always writable, so the writability check
51218 * above is pointless for them. The check could be avoided with some
51219 * refactoring but is probably not worth it.
51220 */
51221
51222 DUK_ASSERT(desc.a_idx >= 0);
51223 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx);
51224 DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv));
51225 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
51226 DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT",
51227 (long) desc.a_idx, (duk_tval *) tv));
51228 }
51229
51230 /* Regardless of whether property is found in entry or array part,
51231 * it may have arguments exotic behavior (array indices may reside
51232 * in entry part for abandoned / non-existent array parts).
51233 */
51234 goto success_with_arguments_exotic;
51235
51236 create_new:
51237
51238 /*
51239 * Create a new property in the original object.
51240 *
51241 * Exotic properties need to be reconsidered here from a write
51242 * perspective (not just property attributes perspective).
51243 * However, the property does not exist in the object already,
51244 * so this limits the kind of exotic properties that apply.
51245 */
51246
51247 /* [key] */
51248
51249 DUK_DDD(DUK_DDDPRINT("create new property to original object"));
51250
51251 DUK_ASSERT(orig != NULL);
51252
51253#if defined(DUK_USE_ROM_OBJECTS)
51254 /* This should not happen because DUK_TAG_OBJECT case checks
51255 * for this already, but check just in case.
51256 */
51257 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
51258 goto fail_not_writable;
51259 }
51260#endif
51261
51262 /* Not possible because array object 'length' is present
51263 * from its creation and cannot be deleted, and is thus
51264 * caught as an existing property above.
51265 */
51266 DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
51267 key == DUK_HTHREAD_STRING_LENGTH(thr)));
51268
51269 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
51270 arr_idx != DUK__NO_ARRAY_INDEX) {
51271 /* automatic length update */
51272 duk_uint32_t old_len;
51273
51274 old_len = duk__get_old_array_length(thr, orig, &desc);
51275
51276 if (arr_idx >= old_len) {
51277 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
51278 "(arr_idx=%ld, old_len=%ld)",
51279 (long) arr_idx, (long) old_len));
51280
51281 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
51282 DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable"));
51283 goto fail_not_writable;
51284 }
51285
51286 /* Note: actual update happens once write has been completed
51287 * without error below. The write should always succeed
51288 * from a specification viewpoint, but we may e.g. run out
51289 * of memory. It's safer in this order.
51290 */
51291
51292 DUK_ASSERT(arr_idx != 0xffffffffUL);
51293 new_array_length = arr_idx + 1; /* flag for later write */
51294 } else {
51295 DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update "
51296 "(arr_idx=%ld, old_len=%ld)",
51297 (long) arr_idx, (long) old_len));
51298 }
51299 }
51300
51301 /* write_to_array_part: */
51302
51303 /*
51304 * Write to array part?
51305 *
51306 * Note: array abandonding requires a property resize which uses
51307 * 'rechecks' valstack for temporaries and may cause any existing
51308 * valstack pointers to be invalidated. To protect against this,
51309 * tv_obj, tv_key, and tv_val are copies of the original inputs.
51310 */
51311
51312 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51313 DUK_HOBJECT_HAS_ARRAY_PART(orig)) {
51314 if (arr_idx < DUK_HOBJECT_GET_ASIZE(orig)) {
51315 goto no_array_growth;
51316 }
51317
51318 /*
51319 * Array needs to grow, but we don't want it becoming too sparse.
51320 * If it were to become sparse, abandon array part, moving all
51321 * array entries into the entries part (for good).
51322 *
51323 * Since we don't keep track of actual density (used vs. size) of
51324 * the array part, we need to estimate somehow. The check is made
51325 * in two parts:
51326 *
51327 * - Check whether the resize need is small compared to the
51328 * current size (relatively); if so, resize without further
51329 * checking (essentially we assume that the original part is
51330 * "dense" so that the result would be dense enough).
51331 *
51332 * - Otherwise, compute the resize using an actual density
51333 * measurement based on counting the used array entries.
51334 */
51335
51336 DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a "
51337 "fast resize without abandon check (arr_idx=%ld, old_size=%ld)",
51338 (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(orig)));
51339
51340 if (duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(orig))) {
51341 duk_uint32_t old_used;
51342 duk_uint32_t old_size;
51343
51344 DUK_DDD(DUK_DDDPRINT("=> fast check is NOT OK, do slow check for array abandon"));
51345
51346 duk__compute_a_stats(thr, orig, &old_used, &old_size);
51347
51348 DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld",
51349 (long) old_used, (long) old_size, (long) arr_idx));
51350
51351 /* Note: intentionally use approximations to shave a few instructions:
51352 * a_used = old_used (accurate: old_used + 1)
51353 * a_size = arr_idx (accurate: arr_idx + 1)
51354 */
51355 if (duk__abandon_array_density_check(old_used, arr_idx)) {
51356 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
51357 "decided to abandon array part (would become too sparse)"));
51358
51359 /* abandoning requires a props allocation resize and
51360 * 'rechecks' the valstack, invalidating any existing
51361 * valstack value pointers!
51362 */
51363 duk__abandon_array_checked(thr, orig);
51364 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig));
51365
51366 goto write_to_entry_part;
51367 }
51368
51369 DUK_DDD(DUK_DDDPRINT("=> decided to keep array part"));
51370 } else {
51371 DUK_DDD(DUK_DDDPRINT("=> fast resize is OK"));
51372 }
51373
51374 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
51375 "decided to extend current allocation"));
51376
51377 duk__grow_props_for_array_item(thr, orig, arr_idx);
51378
51379 no_array_growth:
51380
51381 /* Note: assume array part is comprehensive, so that either
51382 * the write goes to the array part, or we've abandoned the
51383 * array above (and will not come here).
51384 */
51385
51386 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(orig));
51387 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(orig));
51388
51389 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, arr_idx);
51390 /* prev value must be unused, no decref */
51391 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
51392 DUK_TVAL_SET_TVAL(tv, tv_val);
51393 DUK_TVAL_INCREF(thr, tv);
51394 DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T",
51395 (long) arr_idx, (duk_tval *) tv));
51396
51397 /* Note: array part values are [[Writable]], [[Enumerable]],
51398 * and [[Configurable]] which matches the required attributes
51399 * here.
51400 */
51401 goto entry_updated;
51402 }
51403
51404 write_to_entry_part:
51405
51406 /*
51407 * Write to entry part
51408 */
51409
51410 /* entry allocation updates hash part and increases the key
51411 * refcount; may need a props allocation resize but doesn't
51412 * 'recheck' the valstack.
51413 */
51414 e_idx = duk__alloc_entry_checked(thr, orig, key);
51415 DUK_ASSERT(e_idx >= 0);
51416
51417 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
51418 /* prev value can be garbage, no decref */
51419 DUK_TVAL_SET_TVAL(tv, tv_val);
51420 DUK_TVAL_INCREF(thr, tv);
51421 DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC);
51422 goto entry_updated;
51423
51424 entry_updated:
51425
51426 /*
51427 * Possible pending array length update, which must only be done
51428 * if the actual entry write succeeded.
51429 */
51430
51431 if (new_array_length > 0) {
51432 /*
51433 * Note: zero works as a "no update" marker because the new length
51434 * can never be zero after a new property is written.
51435 *
51436 * Note: must re-lookup because calls above (e.g. duk__alloc_entry_checked())
51437 * may realloc and compact properties and hence change e_idx.
51438 */
51439
51440 DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld",
51441 (long) new_array_length));
51442
51443 rc = duk__get_own_propdesc_raw(thr, orig, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &desc, 0 /*flags*/); /* don't push value */
51444 DUK_UNREF(rc);
51445 DUK_ASSERT(rc != 0);
51446 DUK_ASSERT(desc.e_idx >= 0);
51447
51448 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
51449 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
51450 /* no need for decref/incref because value is a number */
51451 DUK_TVAL_SET_FASTINT_U32(tv, new_array_length);
51452 }
51453
51454 /*
51455 * Arguments exotic behavior not possible for new properties: all
51456 * magically bound properties are initially present in the arguments
51457 * object, and if they are deleted, the binding is also removed from
51458 * parameter map.
51459 */
51460
51461 goto success_no_arguments_exotic;
51462
51463 success_with_arguments_exotic:
51464
51465 /*
51466 * Arguments objects have exotic [[DefineOwnProperty]] which updates
51467 * the internal 'map' of arguments for writes to currently mapped
51468 * arguments. More conretely, writes to mapped arguments generate
51469 * a write to a bound variable.
51470 *
51471 * The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing
51472 * data properties and new properties, but not for existing accessors.
51473 * Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we
51474 * have a Desc with 'Value' (and possibly other properties too), and
51475 * we end up in step 5.b.i.
51476 */
51477
51478 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51479 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
51480 /* Note: only numbered indices are relevant, so arr_idx fast reject
51481 * is good (this is valid unless there are more than 4**32-1 arguments).
51482 */
51483
51484 DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed"));
51485
51486 /* Note: we can reuse 'desc' here */
51487
51488 /* XXX: top of stack must contain value, which helper doesn't touch,
51489 * rework to use tv_val directly?
51490 */
51491
51492 duk_push_tval(ctx, tv_val);
51493 (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
51494 duk_pop(ctx);
51495 }
51496 /* fall thru */
51497
51498 success_no_arguments_exotic:
51499 /* shared exit path now */
51500 DUK_DDD(DUK_DDDPRINT("result: success"));
51501 duk_pop(ctx); /* remove key */
51502 return 1;
51503
51504#if defined(DUK_USE_ES6_PROXY)
51505 fail_proxy_rejected:
51506 DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects"));
51507 if (throw_flag) {
51508 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
51509 }
51510 /* Note: no key on stack */
51511 return 0;
51512#endif
51513
51514 fail_base_primitive:
51515 DUK_DDD(DUK_DDDPRINT("result: error, base primitive"));
51516 if (throw_flag) {
51517#if defined(DUK_USE_PARANOID_ERRORS)
51518 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
51519#else
51520 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
51521 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
51522#endif
51523 }
51524 duk_pop(ctx); /* remove key */
51525 return 0;
51526
51527 fail_not_extensible:
51528 DUK_DDD(DUK_DDDPRINT("result: error, not extensible"));
51529 if (throw_flag) {
51530 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
51531 }
51532 duk_pop(ctx); /* remove key */
51533 return 0;
51534
51535 fail_not_writable:
51536 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
51537 if (throw_flag) {
51538 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
51539 }
51540 duk_pop(ctx); /* remove key */
51541 return 0;
51542
51543#if defined(DUK_USE_ROM_OBJECTS)
51544 fail_not_writable_no_pop:
51545 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
51546 if (throw_flag) {
51547 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
51548 }
51549 return 0;
51550#endif
51551
51552 fail_array_length_partial:
51553 DUK_DDD(DUK_DDDPRINT("result: error, array length write only partially successful"));
51554 if (throw_flag) {
51555 DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
51556 }
51557 duk_pop(ctx); /* remove key */
51558 return 0;
51559
51560 fail_no_setter:
51561 DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter"));
51562 if (throw_flag) {
51563 DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
51564 }
51565 duk_pop(ctx); /* remove key */
51566 return 0;
51567
51568 fail_internal:
51569 DUK_DDD(DUK_DDDPRINT("result: error, internal"));
51570 if (throw_flag) {
51571 DUK_ERROR_INTERNAL_DEFMSG(thr);
51572 }
51573 duk_pop(ctx); /* remove key */
51574 return 0;
51575}
51576
51577/*
51578 * Ecmascript compliant [[Delete]](P, Throw).
51579 */
51580
51581DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
51582 duk_propdesc desc;
51583 duk_tval *tv;
51584 duk_uint32_t arr_idx;
51585 duk_bool_t throw_flag;
51586 duk_bool_t force_flag;
51587
51588 throw_flag = (flags & DUK_DELPROP_FLAG_THROW);
51589 force_flag = (flags & DUK_DELPROP_FLAG_FORCE);
51590
51591 DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)",
51592 (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag,
51593 (duk_heaphdr *) obj, (duk_heaphdr *) key));
51594
51595 DUK_ASSERT(thr != NULL);
51596 DUK_ASSERT(thr->heap != NULL);
51597 DUK_ASSERT(obj != NULL);
51598 DUK_ASSERT(key != NULL);
51599
51600 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51601
51602 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
51603
51604 /* 0 = don't push current value */
51605 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
51606 DUK_DDD(DUK_DDDPRINT("property not found, succeed always"));
51607 goto success;
51608 }
51609
51610#if defined(DUK_USE_ROM_OBJECTS)
51611 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
51612 DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object"));
51613 goto fail_not_configurable;
51614 }
51615#endif
51616
51617 if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) {
51618 goto fail_not_configurable;
51619 }
51620 if (desc.a_idx < 0 && desc.e_idx < 0) {
51621 /* Currently there are no deletable virtual properties, but
51622 * with force_flag we might attempt to delete one.
51623 */
51624 goto fail_virtual;
51625 }
51626
51627 if (desc.a_idx >= 0) {
51628 DUK_ASSERT(desc.e_idx < 0);
51629
51630 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
51631 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
51632 goto success;
51633 } else {
51634 duk_hobject *h_get = NULL;
51635 duk_hobject *h_set = NULL;
51636 duk_tval tv_tmp;
51637
51638 DUK_ASSERT(desc.a_idx < 0);
51639
51640 /* Set property slot to an empty state. Careful not to invoke
51641 * any side effects while using desc.e_idx so that it doesn't
51642 * get invalidated by a finalizer mutating our object.
51643 */
51644
51645 /* remove hash entry (no decref) */
51646#if defined(DUK_USE_HOBJECT_HASH_PART)
51647 if (desc.h_idx >= 0) {
51648 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
51649
51650 DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld", (long) desc.h_idx));
51651 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0);
51652 DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj));
51653 h_base[desc.h_idx] = DUK__HASH_DELETED;
51654 } else {
51655 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
51656 }
51657#else
51658 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
51659#endif
51660
51661 /* remove value */
51662 DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
51663 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
51664 DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
51665 DUK_MEMSET((void *) &tv_tmp, 0, sizeof(tv_tmp));
51666 DUK_TVAL_SET_UNDEFINED(&tv_tmp);
51667 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
51668 h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
51669 h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
51670 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
51671 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
51672 } else {
51673 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
51674 DUK_TVAL_SET_TVAL(&tv_tmp, tv);
51675 DUK_TVAL_SET_UNDEFINED(tv);
51676 }
51677#if 0
51678 /* Not strictly necessary because if key == NULL, flag MUST be ignored. */
51679 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0);
51680#endif
51681
51682 /* remove key */
51683 DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p",
51684 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
51685 DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
51686 DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
51687 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
51688
51689 /* Do decrefs only with safe pointers to avoid side effects
51690 * disturbing e_idx.
51691 */
51692 DUK_TVAL_DECREF(thr, &tv_tmp);
51693 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get);
51694 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set);
51695 DUK_HSTRING_DECREF(thr, key);
51696 goto success;
51697 }
51698
51699 DUK_UNREACHABLE();
51700
51701 success:
51702 /*
51703 * Argument exotic [[Delete]] behavior (E5 Section 10.6) is
51704 * a post-check, keeping arguments internal 'map' in sync with
51705 * any successful deletes (note that property does not need to
51706 * exist for delete to 'succeed').
51707 *
51708 * Delete key from 'map'. Since 'map' only contains array index
51709 * keys, we can use arr_idx for a fast skip.
51710 */
51711
51712 DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior"));
51713
51714 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
51715 /* Note: only numbered indices are relevant, so arr_idx fast reject
51716 * is good (this is valid unless there are more than 4**32-1 arguments).
51717 */
51718
51719 DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed"));
51720
51721 /* Note: we can reuse 'desc' here */
51722 (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc);
51723 }
51724
51725 DUK_DDD(DUK_DDDPRINT("delete successful"));
51726 return 1;
51727
51728 fail_virtual:
51729 DUK_DDD(DUK_DDDPRINT("delete failed: property found, force flag, but virtual"));
51730
51731 if (throw_flag) {
51732 DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
51733 }
51734 return 0;
51735
51736 fail_not_configurable:
51737 DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable"));
51738
51739 if (throw_flag) {
51740 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
51741 }
51742 return 0;
51743}
51744
51745/*
51746 * DELPROP: Ecmascript property deletion.
51747 */
51748
51749DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
51750 duk_context *ctx = (duk_context *) thr;
51751 duk_hstring *key = NULL;
51752#if defined(DUK_USE_ES6_PROXY)
51753 duk_propdesc desc;
51754#endif
51755 duk_int_t entry_top;
51756 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
51757 duk_bool_t rc;
51758
51759 DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
51760 (void *) thr, (void *) tv_obj, (void *) tv_key,
51761 (duk_tval *) tv_obj, (duk_tval *) tv_key));
51762
51763 DUK_ASSERT(ctx != NULL);
51764 DUK_ASSERT(thr != NULL);
51765 DUK_ASSERT(thr->heap != NULL);
51766 DUK_ASSERT(tv_obj != NULL);
51767 DUK_ASSERT(tv_key != NULL);
51768
51769 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51770
51771 /* Storing the entry top is cheaper here to ensure stack is correct at exit,
51772 * as there are several paths out.
51773 */
51774 entry_top = duk_get_top(ctx);
51775
51776 if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
51777 DUK_TVAL_IS_NULL(tv_obj)) {
51778 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
51779 goto fail_invalid_base_uncond;
51780 }
51781
51782 duk_push_tval(ctx, tv_obj);
51783 duk_push_tval(ctx, tv_key);
51784
51785 tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -2);
51786 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
51787 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
51788 DUK_ASSERT(obj != NULL);
51789
51790#if defined(DUK_USE_ES6_PROXY)
51791 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
51792 duk_hobject *h_target;
51793 duk_bool_t tmp_bool;
51794
51795 /* Note: proxy handling must happen before key is string coerced. */
51796
51797 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
51798 /* -> [ ... obj key trap handler ] */
51799 DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
51800 duk_push_hobject(ctx, h_target); /* target */
51801 duk_dup(ctx, -4); /* P */
51802 duk_call_method(ctx, 2 /*nargs*/);
51803 tmp_bool = duk_to_boolean(ctx, -1);
51804 duk_pop(ctx);
51805 if (!tmp_bool) {
51806 goto fail_proxy_rejected; /* retval indicates delete failed */
51807 }
51808
51809 /* Target object must be checked for a conflicting
51810 * non-configurable property.
51811 */
51812 tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
51813 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
51814 DUK_ASSERT(key != NULL);
51815
51816 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
51817 int desc_reject;
51818
51819 DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for "
51820 "conflicting property; desc.flags=0x%08lx, "
51821 "desc.get=%p, desc.set=%p",
51822 (duk_heaphdr *) key, (unsigned long) desc.flags,
51823 (void *) desc.get, (void *) desc.set));
51824
51825 desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE);
51826 if (desc_reject) {
51827 /* unconditional */
51828 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
51829 }
51830 }
51831 rc = 1; /* success */
51832 goto done_rc;
51833 }
51834
51835 obj = h_target; /* resume delete to target */
51836 }
51837#endif /* DUK_USE_ES6_PROXY */
51838
51839 duk_to_string(ctx, -1);
51840 key = duk_get_hstring(ctx, -1);
51841 DUK_ASSERT(key != NULL);
51842
51843 rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
51844 goto done_rc;
51845 } else if (DUK_TVAL_IS_STRING(tv_obj)) {
51846 /* XXX: unnecessary string coercion for array indices,
51847 * intentional to keep small.
51848 */
51849 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
51850 DUK_ASSERT(h != NULL);
51851
51852 duk_to_string(ctx, -1);
51853 key = duk_get_hstring(ctx, -1);
51854 DUK_ASSERT(key != NULL);
51855
51856 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51857 goto fail_not_configurable;
51858 }
51859
51860 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
51861
51862 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51863 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
51864 goto fail_not_configurable;
51865 }
51866 } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
51867 /* XXX: unnecessary string coercion for array indices,
51868 * intentional to keep small; some overlap with string
51869 * handling.
51870 */
51871 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
51872 DUK_ASSERT(h != NULL);
51873
51874 duk_to_string(ctx, -1);
51875 key = duk_get_hstring(ctx, -1);
51876 DUK_ASSERT(key != NULL);
51877
51878 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51879 goto fail_not_configurable;
51880 }
51881
51882 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
51883
51884 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51885 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
51886 goto fail_not_configurable;
51887 }
51888 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
51889 /* Lightfunc virtual properties are non-configurable, so
51890 * reject if match any of them.
51891 */
51892
51893 duk_to_string(ctx, -1);
51894 key = duk_get_hstring(ctx, -1);
51895 DUK_ASSERT(key != NULL);
51896
51897 if (duk__key_is_lightfunc_ownprop(thr, key)) {
51898 goto fail_not_configurable;
51899 }
51900 }
51901
51902 /* non-object base, no offending virtual property */
51903 rc = 1;
51904 goto done_rc;
51905
51906 done_rc:
51907 duk_set_top(ctx, entry_top);
51908 return rc;
51909
51910 fail_invalid_base_uncond:
51911 /* Note: unconditional throw */
51912 DUK_ASSERT(duk_get_top(ctx) == entry_top);
51913#if defined(DUK_USE_PARANOID_ERRORS)
51914 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
51915#else
51916 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
51917 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
51918#endif
51919 return 0;
51920
51921#if defined(DUK_USE_ES6_PROXY)
51922 fail_proxy_rejected:
51923 if (throw_flag) {
51924 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
51925 }
51926 duk_set_top(ctx, entry_top);
51927 return 0;
51928#endif
51929
51930 fail_not_configurable:
51931 if (throw_flag) {
51932 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
51933 }
51934 duk_set_top(ctx, entry_top);
51935 return 0;
51936}
51937
51938/*
51939 * Internal helper to define a property with specific flags, ignoring
51940 * normal semantics such as extensibility, write protection etc.
51941 * Overwrites any existing value and attributes unless caller requests
51942 * that value only be updated if it doesn't already exists.
51943 *
51944 * Does not support:
51945 * - virtual properties (error if write attempted)
51946 * - getter/setter properties (error if write attempted)
51947 * - non-default (!= WEC) attributes for array entries (error if attempted)
51948 * - array abandoning: if array part exists, it is always extended
51949 * - array 'length' updating
51950 *
51951 * Stack: [... in_val] -> []
51952 *
51953 * Used for e.g. built-in initialization and environment record
51954 * operations.
51955 */
51956
51957DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
51958 duk_context *ctx = (duk_context *) thr;
51959 duk_propdesc desc;
51960 duk_uint32_t arr_idx;
51961 duk_int_t e_idx;
51962 duk_tval *tv1 = NULL;
51963 duk_tval *tv2 = NULL;
51964 duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */
51965
51966 DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
51967 (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
51968 (unsigned long) flags, (duk_tval *) duk_get_tval(ctx, -1)));
51969
51970 DUK_ASSERT(thr != NULL);
51971 DUK_ASSERT(thr->heap != NULL);
51972 DUK_ASSERT(obj != NULL);
51973 DUK_ASSERT(key != NULL);
51974 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
51975 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51976 DUK_ASSERT(duk_is_valid_index(ctx, -1)); /* contains value */
51977
51978 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
51979
51980 if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
51981 if (desc.e_idx >= 0) {
51982 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
51983 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested"));
51984 goto pop_exit;
51985 }
51986 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes"));
51987 if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) {
51988 DUK_D(DUK_DPRINT("existing property is an accessor, not supported"));
51989 goto error_internal;
51990 }
51991
51992 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags);
51993 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
51994 } else if (desc.a_idx >= 0) {
51995 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
51996 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested"));
51997 goto pop_exit;
51998 }
51999 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)"));
52000 if (propflags != DUK_PROPDESC_FLAGS_WEC) {
52001 DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)",
52002 (unsigned long) propflags));
52003 goto error_internal;
52004 }
52005
52006 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
52007 } else {
52008 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
52009 DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested"));
52010 goto pop_exit;
52011 }
52012 DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> failure"));
52013 goto error_virtual;
52014 }
52015
52016 goto write_value;
52017 }
52018
52019 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
52020 if (arr_idx != DUK__NO_ARRAY_INDEX) {
52021 DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)"));
52022 DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
52023
52024 /* always grow the array, no sparse / abandon support here */
52025 if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
52026 duk__grow_props_for_array_item(thr, obj, arr_idx);
52027 }
52028
52029 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
52030 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
52031 goto write_value;
52032 }
52033 }
52034
52035 DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
52036 e_idx = duk__alloc_entry_checked(thr, obj, key); /* increases key refcount */
52037 DUK_ASSERT(e_idx >= 0);
52038 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
52039 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
52040 /* new entry: previous value is garbage; set to undefined to share write_value */
52041 DUK_TVAL_SET_UNDEFINED(tv1);
52042 goto write_value;
52043
52044 write_value:
52045 /* tv1 points to value storage */
52046
52047 tv2 = duk_require_tval(ctx, -1); /* late lookup, avoid side effects */
52048 DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
52049 (duk_tval *) tv1, (duk_tval *) tv2));
52050
52051 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
52052 goto pop_exit;
52053
52054 pop_exit:
52055 duk_pop(ctx); /* remove in_val */
52056 return;
52057
52058 error_internal:
52059 DUK_ERROR_INTERNAL_DEFMSG(thr);
52060 return;
52061
52062 error_virtual:
52063 DUK_ERROR_TYPE(thr, DUK_STR_REDEFINE_VIRT_PROP);
52064 return;
52065}
52066
52067/*
52068 * Fast path for defining array indexed values without interning the key.
52069 * This is used by e.g. code for Array prototype and traceback creation so
52070 * must avoid interning.
52071 */
52072
52073DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
52074 duk_context *ctx = (duk_context *) thr;
52075 duk_hstring *key;
52076 duk_tval *tv1, *tv2;
52077
52078 DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
52079 "arr_idx=%ld, flags=0x%02lx, val=%!T",
52080 (void *) thr, obj, (long) arr_idx, (unsigned long) flags,
52081 (duk_tval *) duk_get_tval(ctx, -1)));
52082
52083 DUK_ASSERT(thr != NULL);
52084 DUK_ASSERT(thr->heap != NULL);
52085 DUK_ASSERT(obj != NULL);
52086 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
52087
52088 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
52089 arr_idx != DUK__NO_ARRAY_INDEX &&
52090 flags == DUK_PROPDESC_FLAGS_WEC) {
52091 DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0); /* covered by comparison */
52092
52093 DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)"));
52094
52095 /* always grow the array, no sparse / abandon support here */
52096 if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
52097 duk__grow_props_for_array_item(thr, obj, arr_idx);
52098 }
52099
52100 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
52101 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
52102 tv2 = duk_require_tval(ctx, -1);
52103
52104 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
52105
52106 duk_pop(ctx); /* [ ...val ] -> [ ... ] */
52107 return;
52108 }
52109
52110 DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
52111
52112 duk_push_uint(ctx, (duk_uint_t) arr_idx);
52113 key = duk_to_hstring(ctx, -1);
52114 DUK_ASSERT(key != NULL);
52115 duk_insert(ctx, -2); /* [ ... val key ] -> [ ... key val ] */
52116
52117 duk_hobject_define_property_internal(thr, obj, key, flags);
52118
52119 duk_pop(ctx); /* [ ... key ] -> [ ... ] */
52120}
52121
52122/*
52123 * Internal helper for defining an accessor property, ignoring
52124 * normal semantics such as extensibility, write protection etc.
52125 * Overwrites any existing value and attributes. This is called
52126 * very rarely, so the implementation first sets a value to undefined
52127 * and then changes the entry to an accessor (this is to save code space).
52128 */
52129
52130DUK_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) {
52131 duk_context *ctx = (duk_context *) thr;
52132 duk_int_t e_idx;
52133 duk_int_t h_idx;
52134
52135 DUK_DDD(DUK_DDDPRINT("define new accessor (internal): thr=%p, obj=%!O, key=%!O, "
52136 "getter=%!O, setter=%!O, flags=0x%02lx",
52137 (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
52138 (duk_heaphdr *) getter, (duk_heaphdr *) setter,
52139 (unsigned long) propflags));
52140
52141 DUK_ASSERT(thr != NULL);
52142 DUK_ASSERT(thr->heap != NULL);
52143 DUK_ASSERT(obj != NULL);
52144 DUK_ASSERT(key != NULL);
52145 DUK_ASSERT((propflags & ~DUK_PROPDESC_FLAGS_MASK) == 0);
52146 /* setter and/or getter may be NULL */
52147 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
52148
52149 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52150
52151 /* force the property to 'undefined' to create a slot for it */
52152 duk_push_undefined(ctx);
52153 duk_hobject_define_property_internal(thr, obj, key, propflags);
52154 duk_hobject_find_existing_entry(thr->heap, obj, key, &e_idx, &h_idx);
52155 DUK_DDD(DUK_DDDPRINT("accessor slot: e_idx=%ld, h_idx=%ld", (long) e_idx, (long) h_idx));
52156 DUK_ASSERT(e_idx >= 0);
52157 DUK_ASSERT((duk_uint32_t) e_idx < DUK_HOBJECT_GET_ENEXT(obj));
52158
52159 /* no need to decref, as previous value is 'undefined' */
52160 DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, e_idx);
52161 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, getter);
52162 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, setter);
52163 DUK_HOBJECT_INCREF_ALLOWNULL(thr, getter);
52164 DUK_HOBJECT_INCREF_ALLOWNULL(thr, setter);
52165}
52166
52167/*
52168 * Internal helpers for managing object 'length'
52169 */
52170
52171/* XXX: awkward helpers */
52172
52173DUK_INTERNAL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length) {
52174 duk_context *ctx = (duk_context *) thr;
52175 duk_push_hobject(ctx, obj);
52176 duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
52177 duk_push_u32(ctx, length);
52178 (void) duk_hobject_putprop(thr,
52179 DUK_GET_TVAL_NEGIDX(ctx, -3),
52180 DUK_GET_TVAL_NEGIDX(ctx, -2),
52181 DUK_GET_TVAL_NEGIDX(ctx, -1),
52182 0);
52183 duk_pop_n(ctx, 3);
52184}
52185
52186DUK_INTERNAL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj) {
52187 duk_hobject_set_length(thr, obj, 0);
52188}
52189
52190DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
52191 duk_context *ctx = (duk_context *) thr;
52192 duk_double_t val;
52193 duk_push_hobject(ctx, obj);
52194 duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
52195 (void) duk_hobject_getprop(thr,
52196 DUK_GET_TVAL_NEGIDX(ctx, -2),
52197 DUK_GET_TVAL_NEGIDX(ctx, -1));
52198 val = duk_to_number(ctx, -1);
52199 duk_pop_n(ctx, 3);
52200 if (val >= 0.0 && val < DUK_DOUBLE_2TO32) {
52201 return (duk_uint32_t) val;
52202 }
52203 return 0;
52204}
52205
52206/*
52207 * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4)
52208 *
52209 * This is an actual function call.
52210 */
52211
52212DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx) {
52213 duk_hthread *thr = (duk_hthread *) ctx;
52214 duk_hobject *obj;
52215 duk_hstring *key;
52216 duk_propdesc pd;
52217 duk_bool_t rc;
52218
52219 DUK_ASSERT(ctx != NULL);
52220 DUK_ASSERT(thr != NULL);
52221 DUK_ASSERT(thr->heap != NULL);
52222
52223 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
52224 (void) duk_to_string(ctx, 1);
52225 key = duk_require_hstring(ctx, 1);
52226
52227 DUK_ASSERT(obj != NULL);
52228 DUK_ASSERT(key != NULL);
52229
52230 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52231
52232 rc = duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE);
52233 if (!rc) {
52234 duk_push_undefined(ctx);
52235
52236 /* [obj key undefined] */
52237 return 1;
52238 }
52239
52240 duk_push_object(ctx);
52241
52242 /* [obj key value desc] */
52243
52244 if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
52245 /* If a setter/getter is missing (undefined), the descriptor must
52246 * still have the property present with the value 'undefined'.
52247 */
52248 if (pd.get) {
52249 duk_push_hobject(ctx, pd.get);
52250 } else {
52251 duk_push_undefined(ctx);
52252 }
52253 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_GET);
52254 if (pd.set) {
52255 duk_push_hobject(ctx, pd.set);
52256 } else {
52257 duk_push_undefined(ctx);
52258 }
52259 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_SET);
52260 } else {
52261 duk_dup(ctx, -2); /* [obj key value desc value] */
52262 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_VALUE);
52263 duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
52264 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_WRITABLE);
52265
52266 /* [obj key value desc] */
52267 }
52268 duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
52269 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
52270 duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
52271 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
52272
52273 /* [obj key value desc] */
52274 return 1;
52275}
52276
52277/*
52278 * NormalizePropertyDescriptor() related helper.
52279 *
52280 * Internal helper which validates and normalizes a property descriptor
52281 * represented as an Ecmascript object (e.g. argument to defineProperty()).
52282 * The output of this conversion is a set of defprop_flags and possibly
52283 * some values pushed on the value stack; some subset of: property value,
52284 * getter, setter. Caller must manage stack top carefully because the
52285 * number of values pushed depends on the input property descriptor.
52286 *
52287 * The original descriptor object must not be altered in the process.
52288 */
52289
52290/* XXX: very basic optimization -> duk_get_prop_stridx_top */
52291
52292DUK_INTERNAL
52293void duk_hobject_prepare_property_descriptor(duk_context *ctx,
52294 duk_idx_t idx_in,
52295 duk_uint_t *out_defprop_flags,
52296 duk_idx_t *out_idx_value,
52297 duk_hobject **out_getter,
52298 duk_hobject **out_setter) {
52299 duk_hthread *thr = (duk_hthread *) ctx;
52300 duk_idx_t idx_value = -1;
52301 duk_hobject *getter = NULL;
52302 duk_hobject *setter = NULL;
52303 duk_bool_t is_data_desc = 0;
52304 duk_bool_t is_acc_desc = 0;
52305 duk_uint_t defprop_flags = 0;
52306
52307 DUK_ASSERT(ctx != NULL);
52308 DUK_ASSERT(out_defprop_flags != NULL);
52309 DUK_ASSERT(out_idx_value != NULL);
52310 DUK_ASSERT(out_getter != NULL);
52311 DUK_ASSERT(out_setter != NULL);
52312
52313 /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
52314 idx_in = duk_require_normalize_index(ctx, idx_in);
52315 (void) duk_require_hobject(ctx, idx_in);
52316
52317 /* The coercion order must match the ToPropertyDescriptor() algorithm
52318 * so that side effects in coercion happen in the correct order.
52319 * (This order also happens to be compatible with duk_def_prop(),
52320 * although it doesn't matter in practice.)
52321 */
52322
52323 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_VALUE)) {
52324 is_data_desc = 1;
52325 defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
52326 idx_value = duk_get_top_index(ctx);
52327 /* Leave 'value' on stack */
52328 } else {
52329 duk_pop(ctx);
52330 }
52331
52332 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
52333 is_data_desc = 1;
52334 if (duk_to_boolean(ctx, -1)) {
52335 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
52336 } else {
52337 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
52338 }
52339 }
52340 duk_pop(ctx);
52341
52342 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_GET)) {
52343 duk_tval *tv = duk_require_tval(ctx, -1);
52344 duk_hobject *h_get;
52345
52346 if (DUK_TVAL_IS_UNDEFINED(tv)) {
52347 /* undefined is accepted */
52348 DUK_ASSERT(getter == NULL);
52349 } else {
52350 /* NOTE: lightfuncs are coerced to full functions because
52351 * lightfuncs don't fit into a property value slot. This
52352 * has some side effects, see test-dev-lightfunc-accessor.js.
52353 */
52354 h_get = duk_get_hobject_or_lfunc_coerce(ctx, -1);
52355 if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
52356 goto type_error;
52357 }
52358 getter = h_get;
52359 }
52360 is_acc_desc = 1;
52361 defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
52362 /* Leave 'getter' on stack */
52363 } else {
52364 duk_pop(ctx);
52365 }
52366
52367 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_SET)) {
52368 duk_tval *tv = duk_require_tval(ctx, -1);
52369 duk_hobject *h_set;
52370
52371 if (DUK_TVAL_IS_UNDEFINED(tv)) {
52372 /* undefined is accepted */
52373 DUK_ASSERT(setter == NULL);
52374 } else {
52375 /* NOTE: lightfuncs are coerced to full functions because
52376 * lightfuncs don't fit into a property value slot. This
52377 * has some side effects, see test-dev-lightfunc-accessor.js.
52378 */
52379 h_set = duk_get_hobject_or_lfunc_coerce(ctx, -1);
52380 if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
52381 goto type_error;
52382 }
52383 setter = h_set;
52384 }
52385 is_acc_desc = 1;
52386 defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
52387 /* Leave 'setter' on stack */
52388 } else {
52389 duk_pop(ctx);
52390 }
52391
52392 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_ENUMERABLE)) {
52393 if (duk_to_boolean(ctx, -1)) {
52394 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
52395 } else {
52396 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
52397 }
52398 }
52399 duk_pop(ctx);
52400
52401 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_CONFIGURABLE)) {
52402 if (duk_to_boolean(ctx, -1)) {
52403 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
52404 } else {
52405 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
52406 }
52407 }
52408 duk_pop(ctx);
52409
52410 if (is_data_desc && is_acc_desc) {
52411 goto type_error;
52412 }
52413
52414 *out_defprop_flags = defprop_flags;
52415 *out_idx_value = idx_value;
52416 *out_getter = getter;
52417 *out_setter = setter;
52418
52419 /* [ ... value? getter? setter? ] */
52420 return;
52421
52422 type_error:
52423 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
52424}
52425
52426/*
52427 * Object.defineProperty() related helper (E5 Section 15.2.3.6)
52428 *
52429 * Inlines all [[DefineOwnProperty]] exotic behaviors.
52430 *
52431 * Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
52432 * implemented directly, but Object.defineProperty() serves its purpose.
52433 * We don't need the [[DefineOwnProperty]] internally and we don't have a
52434 * property descriptor with 'missing values' so it's easier to avoid it
52435 * entirely.
52436 *
52437 * Note: this is only called for actual objects, not primitive values.
52438 * This must support virtual properties for full objects (e.g. Strings)
52439 * but not for plain values (e.g. strings). Lightfuncs, even though
52440 * primitive in a sense, are treated like objects and accepted as target
52441 * values.
52442 */
52443
52444/* XXX: this is a major target for size optimization */
52445DUK_INTERNAL
52446void duk_hobject_define_property_helper(duk_context *ctx,
52447 duk_uint_t defprop_flags,
52448 duk_hobject *obj,
52449 duk_hstring *key,
52450 duk_idx_t idx_value,
52451 duk_hobject *get,
52452 duk_hobject *set) {
52453 duk_hthread *thr = (duk_hthread *) ctx;
52454 duk_uint32_t arr_idx;
52455 duk_tval tv;
52456 duk_bool_t has_enumerable;
52457 duk_bool_t has_configurable;
52458 duk_bool_t has_writable;
52459 duk_bool_t has_value;
52460 duk_bool_t has_get;
52461 duk_bool_t has_set;
52462 duk_bool_t is_enumerable;
52463 duk_bool_t is_configurable;
52464 duk_bool_t is_writable;
52465 duk_bool_t throw_flag;
52466 duk_bool_t force_flag;
52467 duk_small_uint_t new_flags;
52468 duk_propdesc curr;
52469 duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */
52470 duk_uint32_t arrlen_old_len;
52471 duk_uint32_t arrlen_new_len;
52472 duk_bool_t pending_write_protect;
52473
52474 DUK_ASSERT(thr != NULL);
52475 DUK_ASSERT(thr->heap != NULL);
52476 DUK_ASSERT(ctx != NULL);
52477 DUK_ASSERT(obj != NULL);
52478 DUK_ASSERT(key != NULL);
52479 /* idx_value may be < 0 (no value), set and get may be NULL */
52480
52481 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52482
52483 /* All the flags fit in 16 bits, so will fit into duk_bool_t. */
52484
52485 has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
52486 has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE);
52487 has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE);
52488 has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE);
52489 has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER);
52490 has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER);
52491 is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE);
52492 is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE);
52493 is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE);
52494 throw_flag = 1; /* Object.defineProperty() calls [[DefineOwnProperty]] with Throw=true */
52495 force_flag = (defprop_flags & DUK_DEFPROP_FORCE);
52496
52497 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
52498
52499 arridx_new_array_length = 0;
52500 pending_write_protect = 0;
52501 arrlen_old_len = 0;
52502 arrlen_new_len = 0;
52503
52504 DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld "
52505 "has_configurable=%ld is_configurable=%ld "
52506 "has_writable=%ld is_writable=%ld "
52507 "has_value=%ld value=%!T "
52508 "has_get=%ld get=%p=%!O "
52509 "has_set=%ld set=%p=%!O "
52510 "arr_idx=%ld",
52511 (long) has_enumerable, (long) is_enumerable,
52512 (long) has_configurable, (long) is_configurable,
52513 (long) has_writable, (long) is_writable,
52514 (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(ctx, idx_value) : NULL),
52515 (long) has_get, (void *) get, (duk_heaphdr *) get,
52516 (long) has_set, (void *) set, (duk_heaphdr *) set,
52517 (long) arr_idx));
52518
52519 /*
52520 * Array exotic behaviors can be implemented at this point. The local variables
52521 * are essentially a 'value copy' of the input descriptor (Desc), which is modified
52522 * by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1).
52523 */
52524
52525 if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
52526 goto skip_array_exotic;
52527 }
52528
52529 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
52530 /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
52531 if (!has_value) {
52532 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior"));
52533 goto skip_array_exotic;
52534 }
52535
52536 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior"));
52537
52538 /*
52539 * Get old and new length
52540 */
52541
52542 /* Note: reuse 'curr' as a temp propdesc */
52543 arrlen_old_len = duk__get_old_array_length(thr, obj, &curr);
52544
52545 duk_dup(ctx, idx_value);
52546 arrlen_new_len = duk__to_new_array_length_checked(thr);
52547 duk_push_u32(ctx, arrlen_new_len);
52548 duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
52549
52550 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
52551
52552 if (arrlen_new_len >= arrlen_old_len) {
52553 /* standard behavior, step 3.f.i */
52554 DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior"));
52555 goto skip_array_exotic;
52556 }
52557 DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior"));
52558
52559 /* XXX: consolidated algorithm step 15.f -> redundant? */
52560 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && !force_flag) {
52561 /* Note: 'curr' refers to 'length' propdesc */
52562 goto fail_not_writable_array_length;
52563 }
52564
52565 /* steps 3.h and 3.i */
52566 if (has_writable && !is_writable) {
52567 DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect"));
52568 is_writable = 1;
52569 pending_write_protect = 1;
52570 }
52571
52572 /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */
52573 } else if (arr_idx != DUK__NO_ARRAY_INDEX) {
52574 /* XXX: any chance of unifying this with the 'length' key handling? */
52575
52576 /* E5 Section 15.4.5.1, step 4 */
52577 duk_uint32_t old_len;
52578
52579 /* Note: use 'curr' as a temp propdesc */
52580 old_len = duk__get_old_array_length(thr, obj, &curr);
52581
52582 if (arr_idx >= old_len) {
52583 DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update "
52584 "(arr_idx=%ld, old_len=%ld)",
52585 (long) arr_idx, (long) old_len));
52586
52587 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
52588 /* Note: 'curr' refers to 'length' propdesc */
52589 goto fail_not_writable_array_length;
52590 }
52591
52592 /* actual update happens once write has been completed without
52593 * error below.
52594 */
52595 DUK_ASSERT(arr_idx != 0xffffffffUL);
52596 arridx_new_array_length = arr_idx + 1;
52597 } else {
52598 DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update "
52599 "(arr_idx=%ld, old_len=%ld) -> standard behavior",
52600 (long) arr_idx, (long) old_len));
52601 }
52602 }
52603 skip_array_exotic:
52604
52605 /* XXX: There is currently no support for writing buffer object
52606 * indexed elements here. Attempt to do so will succeed and
52607 * write a concrete property into the buffer object. This should
52608 * be fixed at some point but because buffers are a custom feature
52609 * anyway, this is relatively unimportant.
52610 */
52611
52612 /*
52613 * Actual Object.defineProperty() default algorithm.
52614 */
52615
52616 /*
52617 * First check whether property exists; if not, simple case. This covers
52618 * steps 1-4.
52619 */
52620
52621 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) {
52622 DUK_DDD(DUK_DDDPRINT("property does not exist"));
52623
52624 if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) {
52625 goto fail_not_extensible;
52626 }
52627
52628 /* XXX: share final setting code for value and flags? difficult because
52629 * refcount code is different. Share entry allocation? But can't allocate
52630 * until array index checked.
52631 */
52632
52633 /* steps 4.a and 4.b are tricky */
52634 if (has_set || has_get) {
52635 duk_int_t e_idx;
52636
52637 DUK_DDD(DUK_DDDPRINT("create new accessor property"));
52638
52639 DUK_ASSERT(has_set || set == NULL);
52640 DUK_ASSERT(has_get || get == NULL);
52641 DUK_ASSERT(!has_value);
52642 DUK_ASSERT(!has_writable);
52643
52644 new_flags = DUK_PROPDESC_FLAG_ACCESSOR; /* defaults, E5 Section 8.6.1, Table 7 */
52645 if (has_enumerable && is_enumerable) {
52646 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
52647 }
52648 if (has_configurable && is_configurable) {
52649 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
52650 }
52651
52652 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
52653 DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array"));
52654 duk__abandon_array_checked(thr, obj);
52655 }
52656
52657 /* write to entry part */
52658 e_idx = duk__alloc_entry_checked(thr, obj, key);
52659 DUK_ASSERT(e_idx >= 0);
52660
52661 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
52662 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set);
52663 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
52664 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
52665
52666 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
52667 goto success_exotics;
52668 } else {
52669 duk_int_t e_idx;
52670 duk_tval *tv2;
52671
52672 DUK_DDD(DUK_DDDPRINT("create new data property"));
52673
52674 DUK_ASSERT(!has_set);
52675 DUK_ASSERT(!has_get);
52676
52677 new_flags = 0; /* defaults, E5 Section 8.6.1, Table 7 */
52678 if (has_writable && is_writable) {
52679 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
52680 }
52681 if (has_enumerable && is_enumerable) {
52682 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
52683 }
52684 if (has_configurable && is_configurable) {
52685 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
52686 }
52687 if (has_value) {
52688 duk_tval *tv_tmp = duk_require_tval(ctx, idx_value);
52689 DUK_TVAL_SET_TVAL(&tv, tv_tmp);
52690 } else {
52691 DUK_TVAL_SET_UNDEFINED(&tv); /* default value */
52692 }
52693
52694 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
52695 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
52696#if 0
52697 DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part"));
52698 /* may become sparse...*/
52699#endif
52700 /* XXX: handling for array part missing now; this doesn't affect
52701 * compliance but causes array entry writes using defineProperty()
52702 * to always abandon array part.
52703 */
52704 }
52705 DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array"));
52706 duk__abandon_array_checked(thr, obj);
52707 /* fall through */
52708 }
52709
52710 /* write to entry part */
52711 e_idx = duk__alloc_entry_checked(thr, obj, key);
52712 DUK_ASSERT(e_idx >= 0);
52713 tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
52714 DUK_TVAL_SET_TVAL(tv2, &tv);
52715 DUK_TVAL_INCREF(thr, tv2);
52716
52717 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
52718 goto success_exotics;
52719 }
52720 DUK_UNREACHABLE();
52721 }
52722
52723 /* we currently assume virtual properties are not configurable (as none of them are) */
52724 DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE));
52725
52726 /* [obj key desc value get set curr_value] */
52727
52728 /*
52729 * Property already exists. Steps 5-6 detect whether any changes need
52730 * to be made.
52731 */
52732
52733 if (has_enumerable) {
52734 if (is_enumerable) {
52735 if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) {
52736 goto need_check;
52737 }
52738 } else {
52739 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
52740 goto need_check;
52741 }
52742 }
52743 }
52744 if (has_configurable) {
52745 if (is_configurable) {
52746 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
52747 goto need_check;
52748 }
52749 } else {
52750 if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
52751 goto need_check;
52752 }
52753 }
52754 }
52755 if (has_value) {
52756 duk_tval *tmp1;
52757 duk_tval *tmp2;
52758
52759 /* attempt to change from accessor to data property */
52760 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52761 goto need_check;
52762 }
52763
52764 tmp1 = duk_require_tval(ctx, -1); /* curr value */
52765 tmp2 = duk_require_tval(ctx, idx_value); /* new value */
52766 if (!duk_js_samevalue(tmp1, tmp2)) {
52767 goto need_check;
52768 }
52769 }
52770 if (has_writable) {
52771 /* attempt to change from accessor to data property */
52772 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52773 goto need_check;
52774 }
52775
52776 if (is_writable) {
52777 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
52778 goto need_check;
52779 }
52780 } else {
52781 if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) {
52782 goto need_check;
52783 }
52784 }
52785 }
52786 if (has_set) {
52787 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52788 if (set != curr.set) {
52789 goto need_check;
52790 }
52791 } else {
52792 goto need_check;
52793 }
52794 }
52795 if (has_get) {
52796 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52797 if (get != curr.get) {
52798 goto need_check;
52799 }
52800 } else {
52801 goto need_check;
52802 }
52803 }
52804
52805 /* property exists, either 'desc' is empty, or all values
52806 * match (SameValue)
52807 */
52808 goto success_no_exotics;
52809
52810 need_check:
52811
52812 /*
52813 * Some change(s) need to be made. Steps 7-11.
52814 */
52815
52816 /* shared checks for all descriptor types */
52817 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52818 if (has_configurable && is_configurable) {
52819 goto fail_not_configurable;
52820 }
52821 if (has_enumerable) {
52822 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
52823 if (!is_enumerable) {
52824 goto fail_not_configurable;
52825 }
52826 } else {
52827 if (is_enumerable) {
52828 goto fail_not_configurable;
52829 }
52830 }
52831 }
52832 }
52833
52834 /* Reject attempt to change virtual properties: not part of the
52835 * standard algorithm, applies currently to e.g. virtual index
52836 * properties of buffer objects (which are virtual but writable).
52837 * (Cannot "force" modification of a virtual property.)
52838 */
52839 if (curr.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
52840 goto fail_virtual;
52841 }
52842
52843 /* Reject attempt to change a read-only object. */
52844#if defined(DUK_USE_ROM_OBJECTS)
52845 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
52846 DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object"));
52847 goto fail_not_configurable;
52848 }
52849#endif
52850
52851 /* descriptor type specific checks */
52852 if (has_set || has_get) {
52853 /* IsAccessorDescriptor(desc) == true */
52854 DUK_ASSERT(!has_writable);
52855 DUK_ASSERT(!has_value);
52856
52857 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52858 /* curr and desc are accessors */
52859 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52860 if (has_set && set != curr.set) {
52861 goto fail_not_configurable;
52862 }
52863 if (has_get && get != curr.get) {
52864 goto fail_not_configurable;
52865 }
52866 }
52867 } else {
52868 duk_bool_t rc;
52869 duk_tval *tv1;
52870 duk_tval tv_tmp;
52871
52872 /* curr is data, desc is accessor */
52873 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52874 goto fail_not_configurable;
52875 }
52876
52877 DUK_DDD(DUK_DDDPRINT("convert property to accessor property"));
52878 if (curr.a_idx >= 0) {
52879 DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
52880 duk__abandon_array_checked(thr, obj);
52881 duk_pop(ctx); /* remove old value */
52882 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
52883 DUK_UNREF(rc);
52884 DUK_ASSERT(rc != 0);
52885 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
52886 }
52887
52888 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
52889
52890 /* Avoid side effects that might disturb curr.e_idx until
52891 * we're done editing the slot.
52892 */
52893 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
52894 DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
52895 DUK_TVAL_SET_UNDEFINED(tv1);
52896
52897 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
52898 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
52899 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
52900 DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx);
52901
52902 DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
52903 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
52904
52905 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
52906
52907 /* re-lookup to update curr.flags
52908 * XXX: would be faster to update directly
52909 */
52910 duk_pop(ctx); /* remove old value */
52911 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
52912 DUK_UNREF(rc);
52913 DUK_ASSERT(rc != 0);
52914 }
52915 } else if (has_value || has_writable) {
52916 /* IsDataDescriptor(desc) == true */
52917 DUK_ASSERT(!has_set);
52918 DUK_ASSERT(!has_get);
52919
52920 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52921 duk_bool_t rc;
52922 duk_hobject *h_get;
52923 duk_hobject *h_set;
52924
52925 /* curr is accessor, desc is data */
52926 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52927 goto fail_not_configurable;
52928 }
52929
52930 /* curr is accessor -> cannot be in array part */
52931 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
52932
52933 DUK_DDD(DUK_DDDPRINT("convert property to data property"));
52934
52935 /* Avoid side effects that might disturb curr.e_idx until
52936 * we're done editing the slot.
52937 */
52938 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
52939 h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
52940 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
52941 h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
52942 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
52943
52944 DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
52945 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
52946 DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx);
52947
52948 DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
52949 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
52950
52951 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get); /* side effects */
52952 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set); /* side effects */
52953
52954 /* re-lookup to update curr.flags
52955 * XXX: would be faster to update directly
52956 */
52957 duk_pop(ctx); /* remove old value */
52958 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
52959 DUK_UNREF(rc);
52960 DUK_ASSERT(rc != 0);
52961 } else {
52962 /* curr and desc are data */
52963 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52964 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) {
52965 goto fail_not_configurable;
52966 }
52967 /* Note: changing from writable to non-writable is OK */
52968 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
52969 duk_tval *tmp1 = duk_require_tval(ctx, -1); /* curr value */
52970 duk_tval *tmp2 = duk_require_tval(ctx, idx_value); /* new value */
52971 if (!duk_js_samevalue(tmp1, tmp2)) {
52972 goto fail_not_configurable;
52973 }
52974 }
52975 }
52976 }
52977 } else {
52978 /* IsGenericDescriptor(desc) == true; this means in practice that 'desc'
52979 * only has [[Enumerable]] or [[Configurable]] flag updates, which are
52980 * allowed at this point.
52981 */
52982
52983 DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set);
52984 }
52985
52986 /*
52987 * Start doing property attributes updates. Steps 12-13.
52988 *
52989 * Start by computing new attribute flags without writing yet.
52990 * Property type conversion is done above if necessary.
52991 */
52992
52993 new_flags = curr.flags;
52994
52995 if (has_enumerable) {
52996 if (is_enumerable) {
52997 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
52998 } else {
52999 new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE;
53000 }
53001 }
53002 if (has_configurable) {
53003 if (is_configurable) {
53004 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
53005 } else {
53006 new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
53007 }
53008 }
53009 if (has_writable) {
53010 if (is_writable) {
53011 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
53012 } else {
53013 new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
53014 }
53015 }
53016
53017 /* XXX: write protect after flag? -> any chance of handling it here? */
53018
53019 DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx",
53020 (unsigned long) new_flags));
53021
53022 /*
53023 * Check whether we need to abandon an array part (if it exists)
53024 */
53025
53026 if (curr.a_idx >= 0) {
53027 duk_bool_t rc;
53028
53029 DUK_ASSERT(curr.e_idx < 0);
53030
53031 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
53032 duk_tval *tv1, *tv2;
53033
53034 DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place"));
53035
53036 DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */
53037 DUK_ASSERT(!has_set);
53038 DUK_ASSERT(!has_get);
53039
53040 tv2 = duk_require_tval(ctx, idx_value);
53041 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
53042 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
53043 goto success_exotics;
53044 }
53045
53046 DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
53047 duk__abandon_array_checked(thr, obj);
53048 duk_pop(ctx); /* remove old value */
53049 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
53050 DUK_UNREF(rc);
53051 DUK_ASSERT(rc != 0);
53052 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
53053 }
53054
53055 DUK_DDD(DUK_DDDPRINT("updating existing property in entry part"));
53056
53057 /* array case is handled comprehensively above */
53058 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
53059
53060 DUK_DDD(DUK_DDDPRINT("update existing property attributes"));
53061 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
53062
53063 if (has_set) {
53064 duk_hobject *tmp;
53065
53066 DUK_DDD(DUK_DDDPRINT("update existing property setter"));
53067 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
53068
53069 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
53070 DUK_UNREF(tmp);
53071 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
53072 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
53073 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
53074 }
53075 if (has_get) {
53076 duk_hobject *tmp;
53077
53078 DUK_DDD(DUK_DDDPRINT("update existing property getter"));
53079 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
53080
53081 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
53082 DUK_UNREF(tmp);
53083 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
53084 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
53085 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
53086 }
53087 if (has_value) {
53088 duk_tval *tv1, *tv2;
53089
53090 DUK_DDD(DUK_DDDPRINT("update existing property value"));
53091 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
53092
53093 tv2 = duk_require_tval(ctx, idx_value);
53094 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
53095 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
53096 }
53097
53098 /*
53099 * Standard algorithm succeeded without errors, check for exotic post-behaviors.
53100 *
53101 * Arguments exotic behavior in E5 Section 10.6 occurs after the standard
53102 * [[DefineOwnProperty]] has completed successfully.
53103 *
53104 * Array exotic behavior in E5 Section 15.4.5.1 is implemented partly
53105 * prior to the default [[DefineOwnProperty]], but:
53106 * - for an array index key (e.g. "10") the final 'length' update occurs here
53107 * - for 'length' key the element deletion and 'length' update occurs here
53108 */
53109
53110 success_exotics:
53111
53112 /* [obj key desc value get set curr_value] */
53113
53114 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
53115 if (arridx_new_array_length > 0) {
53116 duk_tval *tmp;
53117 duk_bool_t rc;
53118
53119 /*
53120 * Note: zero works as a "no update" marker because the new length
53121 * can never be zero after a new property is written.
53122 */
53123
53124 /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */
53125
53126 DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld",
53127 (long) arridx_new_array_length));
53128
53129 /* Note: reuse 'curr' */
53130 rc = duk__get_own_propdesc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &curr, 0 /*flags*/); /* don't push value */
53131 DUK_UNREF(rc);
53132 DUK_ASSERT(rc != 0);
53133 DUK_ASSERT(curr.e_idx >= 0);
53134
53135 tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
53136 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
53137 /* no need for decref/incref because value is a number */
53138 DUK_TVAL_SET_FASTINT_U32(tmp, arridx_new_array_length);
53139 }
53140 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
53141 /*
53142 * E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines
53143 * the error case 3.l.iii and the success case 3.m-3.n.
53144 *
53145 * Note: 'length' is always in entries part, so no array abandon issues for
53146 * 'writable' update.
53147 */
53148
53149 /* XXX: investigate whether write protect can be handled above, if we
53150 * just update length here while ignoring its protected status
53151 */
53152
53153 duk_tval *tmp;
53154 duk_uint32_t result_len;
53155 duk_bool_t rc;
53156
53157 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, "
53158 "doing array element deletion and length update"));
53159
53160 rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len);
53161
53162 /* update length (curr points to length, and we assume it's still valid) */
53163 DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
53164
53165 DUK_ASSERT(curr.e_idx >= 0);
53166 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
53167 tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
53168 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
53169 /* no decref needed for a number */
53170 DUK_TVAL_SET_FASTINT_U32(tmp, result_len);
53171 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
53172
53173 if (pending_write_protect) {
53174 DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)"));
53175 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
53176 }
53177
53178 /*
53179 * XXX: shrink array allocation or entries compaction here?
53180 */
53181
53182 if (!rc) {
53183 goto fail_array_length_partial;
53184 }
53185 }
53186 } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
53187 duk_hobject *map;
53188 duk_hobject *varenv;
53189
53190 DUK_ASSERT(arridx_new_array_length == 0);
53191 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); /* traits are separate; in particular, arguments not an array */
53192
53193 map = NULL;
53194 varenv = NULL;
53195 if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) {
53196 goto success_no_exotics;
53197 }
53198 DUK_ASSERT(map != NULL);
53199 DUK_ASSERT(varenv != NULL);
53200
53201 /* [obj key desc value get set curr_value varname] */
53202
53203 if (has_set || has_get) {
53204 /* = IsAccessorDescriptor(Desc) */
53205 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' "
53206 "changed to an accessor, delete arguments binding"));
53207
53208 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
53209 } else {
53210 /* Note: this order matters (final value before deleting map entry must be done) */
53211 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
53212 "check for value update / binding deletion"));
53213
53214 if (has_value) {
53215 duk_hstring *varname;
53216
53217 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
53218 "update bound value (variable/argument)"));
53219
53220 varname = duk_require_hstring(ctx, -1);
53221 DUK_ASSERT(varname != NULL);
53222
53223 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
53224 "key=%!O, varname=%!O, value=%!T",
53225 (duk_heaphdr *) key,
53226 (duk_heaphdr *) varname,
53227 (duk_tval *) duk_require_tval(ctx, idx_value)));
53228
53229 /* strict flag for putvar comes from our caller (currently: fixed) */
53230 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, idx_value), throw_flag);
53231 }
53232 if (has_writable && !is_writable) {
53233 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
53234 "changed to non-writable, delete arguments binding"));
53235
53236 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
53237 }
53238 }
53239
53240 /* 'varname' is in stack in this else branch, leaving an unbalanced stack below,
53241 * but this doesn't matter now.
53242 */
53243 }
53244
53245 success_no_exotics:
53246 return;
53247
53248 fail_virtual:
53249 DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
53250 return;
53251
53252 fail_not_writable_array_length:
53253 DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_NOT_WRITABLE);
53254 return;
53255
53256 fail_not_extensible:
53257 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
53258 return;
53259
53260 fail_not_configurable:
53261 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
53262 return;
53263
53264 fail_array_length_partial:
53265 DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
53266 return;
53267}
53268
53269/*
53270 * Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
53271 */
53272
53273DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags) {
53274 duk_hthread *thr = (duk_hthread *) ctx;
53275 duk_hstring *h_v;
53276 duk_hobject *h_obj;
53277 duk_propdesc desc;
53278 duk_bool_t ret;
53279
53280 /* coercion order matters */
53281 h_v = duk_to_hstring(ctx, 0);
53282 DUK_ASSERT(h_v != NULL);
53283
53284 h_obj = duk_push_this_coercible_to_object(ctx);
53285 DUK_ASSERT(h_obj != NULL);
53286
53287 ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */
53288
53289 duk_push_boolean(ctx, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
53290 return 1;
53291}
53292
53293/*
53294 * Object.seal() and Object.freeze() (E5 Sections 15.2.3.8 and 15.2.3.9)
53295 *
53296 * Since the algorithms are similar, a helper provides both functions.
53297 * Freezing is essentially sealing + making plain properties non-writable.
53298 *
53299 * Note: virtual (non-concrete) properties which are non-configurable but
53300 * writable would pose some problems, but such properties do not currently
53301 * exist (all virtual properties are non-configurable and non-writable).
53302 * If they did exist, the non-configurability does NOT prevent them from
53303 * becoming non-writable. However, this change should be recorded somehow
53304 * so that it would turn up (e.g. when getting the property descriptor),
53305 * requiring some additional flags in the object.
53306 */
53307
53308DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) {
53309 duk_uint_fast32_t i;
53310
53311 DUK_ASSERT(thr != NULL);
53312 DUK_ASSERT(thr->heap != NULL);
53313 DUK_ASSERT(obj != NULL);
53314
53315 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
53316
53317#if defined(DUK_USE_ROM_OBJECTS)
53318 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
53319 DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject"));
53320 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
53321 }
53322#endif
53323
53324 /*
53325 * Abandon array part because all properties must become non-configurable.
53326 * Note that this is now done regardless of whether this is always the case
53327 * (skips check, but performance problem if caller would do this many times
53328 * for the same object; not likely).
53329 */
53330
53331 duk__abandon_array_checked(thr, obj);
53332 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0);
53333
53334 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
53335 duk_uint8_t *fp;
53336
53337 /* since duk__abandon_array_checked() causes a resize, there should be no gaps in keys */
53338 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL);
53339
53340 /* avoid multiple computations of flags address; bypasses macros */
53341 fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i);
53342 if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) {
53343 *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE);
53344 } else {
53345 *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
53346 }
53347 }
53348
53349 DUK_HOBJECT_CLEAR_EXTENSIBLE(obj);
53350
53351 /* no need to compact since we already did that in duk__abandon_array_checked()
53352 * (regardless of whether an array part existed or not.
53353 */
53354
53355 return;
53356}
53357
53358/*
53359 * Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13)
53360 *
53361 * Since the algorithms are similar, a helper provides both functions.
53362 * Freezing is essentially sealing + making plain properties non-writable.
53363 *
53364 * Note: all virtual (non-concrete) properties are currently non-configurable
53365 * and non-writable (and there are no accessor virtual properties), so they don't
53366 * need to be considered here now.
53367 */
53368
53369DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) {
53370 duk_uint_fast32_t i;
53371
53372 DUK_ASSERT(obj != NULL);
53373 DUK_UNREF(thr);
53374
53375 /* Note: no allocation pressure, no need to check refcounts etc */
53376
53377 /* must not be extensible */
53378 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
53379 return 0;
53380 }
53381
53382 /* all virtual properties are non-configurable and non-writable */
53383
53384 /* entry part must not contain any configurable properties, or
53385 * writable properties (if is_frozen).
53386 */
53387 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
53388 duk_small_uint_t flags;
53389
53390 if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) {
53391 continue;
53392 }
53393
53394 /* avoid multiple computations of flags address; bypasses macros */
53395 flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
53396
53397 if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
53398 return 0;
53399 }
53400 if (is_frozen &&
53401 !(flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
53402 (flags & DUK_PROPDESC_FLAG_WRITABLE)) {
53403 return 0;
53404 }
53405 }
53406
53407 /* array part must not contain any non-unused properties, as they would
53408 * be configurable and writable.
53409 */
53410 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
53411 duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
53412 if (!DUK_TVAL_IS_UNUSED(tv)) {
53413 return 0;
53414 }
53415 }
53416
53417 return 1;
53418}
53419
53420/*
53421 * Object.preventExtensions() and Object.isExtensible() (E5 Sections 15.2.3.10, 15.2.3.13)
53422 *
53423 * Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE
53424 * and the Object built-in bindings.
53425 */
53426
53427/* Undefine local defines */
53428
53429#undef DUK__NO_ARRAY_INDEX
53430#undef DUK__HASH_INITIAL
53431#undef DUK__HASH_PROBE_STEP
53432#undef DUK__HASH_UNUSED
53433#undef DUK__HASH_DELETED
53434#undef DUK__VALSTACK_SPACE
53435#line 1 "duk_hstring_misc.c"
53436/*
53437 * Misc support functions
53438 */
53439
53440/* include removed: duk_internal.h */
53441
53442DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos) {
53443 duk_uint32_t boff;
53444 const duk_uint8_t *p, *p_start, *p_end;
53445 duk_ucodepoint_t cp;
53446
53447 /* Caller must check character offset to be inside the string. */
53448 DUK_ASSERT(thr != NULL);
53449 DUK_ASSERT(h != NULL);
53450 DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */
53451 DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
53452
53453 boff = duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
53454 DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
53455 (long) pos, (long) boff, (duk_heaphdr *) h));
53456 DUK_ASSERT_DISABLE(boff >= 0);
53457 DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h));
53458
53459 p_start = DUK_HSTRING_GET_DATA(h);
53460 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
53461 p = p_start + boff;
53462 DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p",
53463 (const void *) p_start, (const void *) p_end,
53464 (const void *) p));
53465
53466 /* This may throw an error though not for valid E5 strings. */
53467 cp = duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
53468 return cp;
53469}
53470
53471#if !defined(DUK_USE_HSTRING_CLEN)
53472DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
53473 if (DUK_HSTRING_HAS_ASCII(h)) {
53474 /* Most practical strings will go here. */
53475 return DUK_HSTRING_GET_BYTELEN(h);
53476 } else {
53477 return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
53478 }
53479}
53480#endif /* !DUK_USE_HSTRING_CLEN */
53481#line 1 "duk_hthread_alloc.c"
53482/*
53483 * duk_hthread allocation and freeing.
53484 */
53485
53486/* include removed: duk_internal.h */
53487
53488/*
53489 * Allocate initial stacks for a thread. Note that 'thr' must be reachable
53490 * as a garbage collection may be triggered by the allocation attempts.
53491 * Returns zero (without leaking memory) if init fails.
53492 */
53493
53494DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
53495 duk_size_t alloc_size;
53496 duk_size_t i;
53497
53498 DUK_ASSERT(heap != NULL);
53499 DUK_ASSERT(thr != NULL);
53500 DUK_ASSERT(thr->valstack == NULL);
53501 DUK_ASSERT(thr->valstack_end == NULL);
53502 DUK_ASSERT(thr->valstack_bottom == NULL);
53503 DUK_ASSERT(thr->valstack_top == NULL);
53504 DUK_ASSERT(thr->callstack == NULL);
53505 DUK_ASSERT(thr->catchstack == NULL);
53506
53507 /* valstack */
53508 alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
53509 thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
53510 if (!thr->valstack) {
53511 goto fail;
53512 }
53513 DUK_MEMZERO(thr->valstack, alloc_size);
53514 thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
53515#if !defined(DUK_USE_PREFER_SIZE)
53516 thr->valstack_size = DUK_VALSTACK_INITIAL_SIZE;
53517#endif
53518 thr->valstack_bottom = thr->valstack;
53519 thr->valstack_top = thr->valstack;
53520
53521 for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
53522 DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
53523 }
53524
53525 /* callstack */
53526 alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
53527 thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
53528 if (!thr->callstack) {
53529 goto fail;
53530 }
53531 DUK_MEMZERO(thr->callstack, alloc_size);
53532 thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
53533 DUK_ASSERT(thr->callstack_top == 0);
53534
53535 /* catchstack */
53536 alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
53537 thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
53538 if (!thr->catchstack) {
53539 goto fail;
53540 }
53541 DUK_MEMZERO(thr->catchstack, alloc_size);
53542 thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
53543 DUK_ASSERT(thr->catchstack_top == 0);
53544
53545 return 1;
53546
53547 fail:
53548 DUK_FREE(heap, thr->valstack);
53549 DUK_FREE(heap, thr->callstack);
53550 DUK_FREE(heap, thr->catchstack);
53551
53552 thr->valstack = NULL;
53553 thr->callstack = NULL;
53554 thr->catchstack = NULL;
53555 return 0;
53556}
53557
53558/* For indirect allocs. */
53559
53560DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
53561 duk_hthread *thr = (duk_hthread *) ud;
53562 DUK_UNREF(heap);
53563 return (void *) thr->valstack;
53564}
53565
53566DUK_INTERNAL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud) {
53567 duk_hthread *thr = (duk_hthread *) ud;
53568 DUK_UNREF(heap);
53569 return (void *) thr->callstack;
53570}
53571
53572DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
53573 duk_hthread *thr = (duk_hthread *) ud;
53574 DUK_UNREF(heap);
53575 return (void *) thr->catchstack;
53576}
53577#line 1 "duk_hthread_builtins.c"
53578/*
53579 * Initialize built-in objects. Current thread must have a valstack
53580 * and initialization errors may longjmp, so a setjmp() catch point
53581 * must exist.
53582 */
53583
53584/* include removed: duk_internal.h */
53585
53586/*
53587 * Encoding constants, must match genbuiltins.py
53588 */
53589
53590#define DUK__CLASS_BITS 5
53591#define DUK__BIDX_BITS 7
53592#define DUK__STRIDX_BITS 9 /* XXX: try to optimize to 8 (would now be possible, <200 used) */
53593#define DUK__NATIDX_BITS 8
53594#define DUK__NUM_NORMAL_PROPS_BITS 6
53595#define DUK__NUM_FUNC_PROPS_BITS 6
53596#define DUK__PROP_FLAGS_BITS 3
53597#define DUK__STRING_LENGTH_BITS 8
53598#define DUK__STRING_CHAR_BITS 7
53599#define DUK__LENGTH_PROP_BITS 3
53600#define DUK__NARGS_BITS 3
53601#define DUK__PROP_TYPE_BITS 3
53602#define DUK__MAGIC_BITS 16
53603
53604#define DUK__NARGS_VARARGS_MARKER 0x07
53605#define DUK__NO_CLASS_MARKER 0x00 /* 0 = DUK_HOBJECT_CLASS_UNUSED */
53606#define DUK__NO_BIDX_MARKER 0x7f
53607#define DUK__NO_STRIDX_MARKER 0xff
53608
53609#define DUK__PROP_TYPE_DOUBLE 0
53610#define DUK__PROP_TYPE_STRING 1
53611#define DUK__PROP_TYPE_STRIDX 2
53612#define DUK__PROP_TYPE_BUILTIN 3
53613#define DUK__PROP_TYPE_UNDEFINED 4
53614#define DUK__PROP_TYPE_BOOLEAN_TRUE 5
53615#define DUK__PROP_TYPE_BOOLEAN_FALSE 6
53616#define DUK__PROP_TYPE_ACCESSOR 7
53617
53618/*
53619 * Create built-in objects by parsing an init bitstream generated
53620 * by genbuiltins.py.
53621 */
53622
53623#if defined(DUK_USE_ROM_OBJECTS)
53624#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
53625DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
53626 duk_context *ctx;
53627 duk_hobject *h1;
53628#if defined(DUK_USE_ROM_GLOBAL_CLONE)
53629 duk_hobject *h2;
53630 duk_uint8_t *props;
53631 duk_size_t alloc_size;
53632#endif
53633
53634 ctx = (duk_context *) thr;
53635
53636 /* XXX: refactor into internal helper, duk_clone_hobject() */
53637
53638#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
53639 /* Inherit from ROM-based global object: less RAM usage, less transparent. */
53640 duk_push_object_helper(ctx,
53641 DUK_HOBJECT_FLAG_EXTENSIBLE |
53642 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
53643 DUK_BIDX_GLOBAL);
53644 h1 = duk_get_hobject(ctx, -1);
53645 DUK_ASSERT(h1 != NULL);
53646#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
53647 /* Clone the properties of the ROM-based global object to create a
53648 * fully RAM-based global object. Uses more memory than the inherit
53649 * model but more compliant.
53650 */
53651 duk_push_object_helper(ctx,
53652 DUK_HOBJECT_FLAG_EXTENSIBLE |
53653 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
53654 DUK_BIDX_OBJECT_PROTOTYPE);
53655 h1 = duk_get_hobject(ctx, -1);
53656 DUK_ASSERT(h1 != NULL);
53657 h2 = thr->builtins[DUK_BIDX_GLOBAL];
53658 DUK_ASSERT(h2 != NULL);
53659
53660 /* Copy the property table verbatim; this handles attributes etc.
53661 * For ROM objects it's not necessary (or possible) to update
53662 * refcounts so leave them as is.
53663 */
53664 alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2);
53665 DUK_ASSERT(alloc_size > 0);
53666 props = DUK_ALLOC(thr->heap, alloc_size);
53667 if (!props) {
53668 DUK_ERROR_ALLOC_DEFMSG(thr);
53669 return;
53670 }
53671 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL);
53672 DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size);
53673
53674 /* XXX: keep property attributes or tweak them here?
53675 * Properties will now be non-configurable even when they're
53676 * normally configurable for the global object.
53677 */
53678
53679 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL);
53680 DUK_HOBJECT_SET_PROPS(thr->heap, h1, props);
53681 DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2));
53682 DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2));
53683 DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2));
53684 DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2));
53685#else
53686#error internal error in defines
53687#endif
53688
53689 duk_hobject_compact_props(thr, h1);
53690 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
53691 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */
53692 thr->builtins[DUK_BIDX_GLOBAL] = h1;
53693 DUK_HOBJECT_INCREF(thr, h1);
53694 DUK_D(DUK_DPRINT("duplicated global object: %!O", h1));
53695
53696
53697 /* Create a fresh object environment for the global scope. This is
53698 * needed so that the global scope points to the newly created RAM-based
53699 * global object.
53700 */
53701 duk_push_object_helper(ctx,
53702 DUK_HOBJECT_FLAG_EXTENSIBLE |
53703 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
53704 -1); /* no prototype */
53705 h1 = duk_get_hobject(ctx, -1);
53706 DUK_ASSERT(h1 != NULL);
53707 duk_dup(ctx, -2); /* -> [ ... new_global new_globalenv new_global ] */
53708 duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
53709 /* provideThis=false */
53710
53711 duk_hobject_compact_props(thr, h1);
53712 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
53713 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */
53714 thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1;
53715 DUK_HOBJECT_INCREF(thr, h1);
53716 DUK_D(DUK_DPRINT("duplicated global env: %!O", h1));
53717
53718 duk_pop_2(ctx);
53719}
53720#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
53721
53722DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
53723 /* Setup builtins from ROM objects. All heaps/threads will share
53724 * the same readonly objects.
53725 */
53726 duk_small_uint_t i;
53727
53728 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
53729 duk_hobject *h;
53730 h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
53731 DUK_ASSERT(h != NULL);
53732 thr->builtins[i] = h;
53733 }
53734
53735#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
53736 /* By default the global object is read-only which is often much
53737 * more of an issue than having read-only built-in objects (like
53738 * RegExp, Date, etc). Use a RAM-based copy of the global object
53739 * and the global environment object for convenience.
53740 */
53741 duk__duplicate_ram_global_object(thr);
53742#endif
53743}
53744#else /* DUK_USE_ROM_OBJECTS */
53745DUK_LOCAL void duk__push_stridx(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53746 duk_small_uint_t n;
53747
53748 n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS);
53749 DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
53750 DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
53751 duk_push_hstring_stridx(ctx, n);
53752}
53753DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53754 duk_small_uint_t n;
53755 duk_small_uint_t i;
53756 duk_uint8_t *p;
53757
53758 n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRING_LENGTH_BITS);
53759 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, n);
53760 for (i = 0; i < n; i++) {
53761 *p++ = (duk_uint8_t) duk_bd_decode(bd, DUK__STRING_CHAR_BITS);
53762 }
53763 duk_to_string(ctx, -1);
53764}
53765DUK_LOCAL void duk__push_stridx_or_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53766 if (duk_bd_decode_flag(bd)) {
53767 duk__push_string(ctx, bd);
53768 } else {
53769 duk__push_stridx(ctx, bd);
53770 }
53771}
53772DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53773 duk_double_union du;
53774 duk_small_uint_t i;
53775
53776 for (i = 0; i < 8; i++) {
53777 /* Encoding endianness must match target memory layout,
53778 * build scripts and genbuiltins.py must ensure this.
53779 */
53780 du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
53781 }
53782
53783 duk_push_number(ctx, du.d); /* push operation normalizes NaNs */
53784}
53785
53786DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
53787 duk_context *ctx = (duk_context *) thr;
53788 duk_bitdecoder_ctx bd_ctx;
53789 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
53790 duk_hobject *h;
53791 duk_small_uint_t i, j;
53792
53793 DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
53794
53795 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
53796 bd->data = (const duk_uint8_t *) duk_builtins_data;
53797 bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
53798
53799 /*
53800 * First create all built-in bare objects on the empty valstack.
53801 *
53802 * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
53803 * stack indices matching their eventual thr->builtins[] index.
53804 *
53805 * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
53806 * will exist on the value stack during init but won't be placed
53807 * into thr->builtins[]. These are objects referenced in some way
53808 * from thr->builtins[] roots but which don't need to be indexed by
53809 * Duktape through thr->builtins[] (e.g. user custom objects).
53810 */
53811
53812 duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS);
53813
53814 DUK_DD(DUK_DDPRINT("create empty built-ins"));
53815 DUK_ASSERT_TOP(ctx, 0);
53816 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
53817 duk_small_uint_t class_num;
53818 duk_small_int_t len = -1; /* must be signed */
53819
53820 class_num = (duk_small_uint_t) duk_bd_decode(bd, DUK__CLASS_BITS);
53821 len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
53822
53823 if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
53824 duk_small_uint_t natidx;
53825 duk_int_t c_nargs; /* must hold DUK_VARARGS */
53826 duk_c_function c_func;
53827 duk_int16_t magic;
53828
53829 DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
53830 DUK_ASSERT(len >= 0);
53831
53832 natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
53833 c_func = duk_bi_native_functions[natidx];
53834
53835 c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/);
53836 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
53837 c_nargs = DUK_VARARGS;
53838 }
53839
53840 /* XXX: set magic directly here? (it could share the c_nargs arg) */
53841 duk_push_c_function_noexotic(ctx, c_func, c_nargs);
53842
53843 h = duk_require_hobject(ctx, -1);
53844 DUK_ASSERT(h != NULL);
53845
53846 /* Currently all built-in native functions are strict.
53847 * duk_push_c_function() now sets strict flag, so
53848 * assert for it.
53849 */
53850 DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
53851
53852 /* XXX: function properties */
53853
53854 /* Built-in 'name' is not writable by default. Function '.name'
53855 * is writable to allow user code to set a '.name' on a native
53856 * function.
53857 */
53858 duk__push_stridx_or_string(ctx, bd);
53859 duk_xdef_prop_stridx(ctx,
53860 -2,
53861 DUK_STRIDX_NAME,
53862 (i == DUK_BIDX_FUNCTION_PROTOTYPE) ?
53863 DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE);
53864
53865 /* Almost all global level Function objects are constructable
53866 * but not all: Function.prototype is a non-constructable,
53867 * callable Function.
53868 */
53869 if (duk_bd_decode_flag(bd)) {
53870 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
53871 } else {
53872 DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
53873 }
53874
53875 /* Cast converts magic to 16-bit signed value */
53876 magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/);
53877 ((duk_hnativefunction *) h)->magic = magic;
53878 } else {
53879 /* XXX: ARRAY_PART for Array prototype? */
53880
53881 duk_push_object_helper(ctx,
53882 DUK_HOBJECT_FLAG_EXTENSIBLE,
53883 -1); /* no prototype or class yet */
53884
53885 h = duk_require_hobject(ctx, -1);
53886 DUK_ASSERT(h != NULL);
53887 }
53888
53889 DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
53890
53891 if (i < DUK_NUM_BUILTINS) {
53892 thr->builtins[i] = h;
53893 DUK_HOBJECT_INCREF(thr, &h->hdr);
53894 }
53895
53896 if (len >= 0) {
53897 /*
53898 * For top-level objects, 'length' property has the following
53899 * default attributes: non-writable, non-enumerable, non-configurable
53900 * (E5 Section 15).
53901 *
53902 * However, 'length' property for Array.prototype has attributes
53903 * expected of an Array instance which are different: writable,
53904 * non-enumerable, non-configurable (E5 Section 15.4.5.2).
53905 *
53906 * This is currently determined implicitly based on class; there are
53907 * no attribute flags in the init data.
53908 */
53909
53910 duk_push_int(ctx, len);
53911 duk_xdef_prop_stridx(ctx,
53912 -2,
53913 DUK_STRIDX_LENGTH,
53914 (class_num == DUK_HOBJECT_CLASS_ARRAY ? /* only Array.prototype matches */
53915 DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE));
53916 }
53917
53918 /* enable exotic behaviors last */
53919
53920 if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
53921 DUK_HOBJECT_SET_EXOTIC_ARRAY(h);
53922 }
53923 if (class_num == DUK_HOBJECT_CLASS_STRING) {
53924 DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
53925 }
53926
53927 /* some assertions */
53928
53929 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
53930 /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
53931 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h));
53932 DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h));
53933 /* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */
53934 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h));
53935 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h)); /* currently, even for Array.prototype */
53936 /* DUK_HOBJECT_FLAG_STRICT varies */
53937 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) || /* all native functions have NEWENV */
53938 DUK_HOBJECT_HAS_NEWENV(h));
53939 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
53940 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
53941 DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h));
53942 /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
53943 /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
53944 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
53945
53946 DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
53947 }
53948
53949 /*
53950 * Then decode the builtins init data (see genbuiltins.py) to
53951 * init objects
53952 */
53953
53954 DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
53955 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
53956 duk_small_uint_t t;
53957 duk_small_uint_t num;
53958
53959 DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
53960 h = duk_require_hobject(ctx, i);
53961 DUK_ASSERT(h != NULL);
53962
53963 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
53964 if (t != DUK__NO_BIDX_MARKER) {
53965 DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
53966 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_require_hobject(ctx, t));
53967 }
53968
53969 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
53970 if (t != DUK__NO_BIDX_MARKER) {
53971 /* 'prototype' property for all built-in objects (which have it) has attributes:
53972 * [[Writable]] = false,
53973 * [[Enumerable]] = false,
53974 * [[Configurable]] = false
53975 */
53976 DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
53977 duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
53978 }
53979
53980 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
53981 if (t != DUK__NO_BIDX_MARKER) {
53982 /* 'constructor' property for all built-in objects (which have it) has attributes:
53983 * [[Writable]] = true,
53984 * [[Enumerable]] = false,
53985 * [[Configurable]] = true
53986 */
53987 DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
53988 duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
53989 }
53990
53991 /* normal valued properties */
53992 num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS);
53993 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
53994 for (j = 0; j < num; j++) {
53995 duk_small_uint_t prop_flags;
53996
53997 duk__push_stridx_or_string(ctx, bd);
53998
53999 /*
54000 * Property attribute defaults are defined in E5 Section 15 (first
54001 * few pages); there is a default for all properties and a special
54002 * default for 'length' properties. Variation from the defaults is
54003 * signaled using a single flag bit in the bitstream.
54004 */
54005
54006 if (duk_bd_decode_flag(bd)) {
54007 prop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
54008 } else {
54009 prop_flags = DUK_PROPDESC_FLAGS_WC;
54010 }
54011
54012 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
54013
54014 DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
54015 (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) prop_flags, (long) t));
54016
54017 switch (t) {
54018 case DUK__PROP_TYPE_DOUBLE: {
54019 duk__push_double(ctx, bd);
54020 break;
54021 }
54022 case DUK__PROP_TYPE_STRING: {
54023 duk__push_string(ctx, bd);
54024 break;
54025 }
54026 case DUK__PROP_TYPE_STRIDX: {
54027 duk__push_stridx(ctx, bd);
54028 break;
54029 }
54030 case DUK__PROP_TYPE_BUILTIN: {
54031 duk_small_uint_t bidx;
54032
54033 bidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
54034 DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER);
54035 duk_dup(ctx, (duk_idx_t) bidx);
54036 break;
54037 }
54038 case DUK__PROP_TYPE_UNDEFINED: {
54039 duk_push_undefined(ctx);
54040 break;
54041 }
54042 case DUK__PROP_TYPE_BOOLEAN_TRUE: {
54043 duk_push_true(ctx);
54044 break;
54045 }
54046 case DUK__PROP_TYPE_BOOLEAN_FALSE: {
54047 duk_push_false(ctx);
54048 break;
54049 }
54050 case DUK__PROP_TYPE_ACCESSOR: {
54051 duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
54052 duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
54053 duk_c_function c_func_getter;
54054 duk_c_function c_func_setter;
54055
54056 /* XXX: this is a bit awkward because there is no exposed helper
54057 * in the API style, only this internal helper.
54058 */
54059 DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
54060 (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags));
54061
54062 c_func_getter = duk_bi_native_functions[natidx_getter];
54063 c_func_setter = duk_bi_native_functions[natidx_setter];
54064 duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
54065 duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
54066
54067 /* XXX: magic for getter/setter? use duk_def_prop()? */
54068
54069 DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */
54070
54071 prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */
54072 duk_hobject_define_accessor_internal(thr,
54073 duk_require_hobject(ctx, i),
54074 duk_get_hstring(ctx, -3),
54075 duk_require_hobject(ctx, -2),
54076 duk_require_hobject(ctx, -1),
54077 prop_flags);
54078 duk_pop_3(ctx); /* key, getter and setter, now reachable through object */
54079 goto skip_value;
54080 }
54081 default: {
54082 /* exhaustive */
54083 DUK_UNREACHABLE();
54084 }
54085 }
54086
54087 DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0);
54088 duk_xdef_prop(ctx, i, prop_flags);
54089
54090 skip_value:
54091 continue; /* avoid empty label at the end of a compound statement */
54092 }
54093
54094 /* native function properties */
54095 num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS);
54096 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
54097 for (j = 0; j < num; j++) {
54098 duk_hstring *h_key;
54099 duk_small_uint_t natidx;
54100 duk_int_t c_nargs; /* must hold DUK_VARARGS */
54101 duk_small_uint_t c_length;
54102 duk_int16_t magic;
54103 duk_c_function c_func;
54104 duk_hnativefunction *h_func;
54105#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54106 duk_small_int_t lightfunc_eligible;
54107#endif
54108
54109 duk__push_stridx_or_string(ctx, bd);
54110 h_key = duk_get_hstring(ctx, -1);
54111 DUK_ASSERT(h_key != NULL);
54112 DUK_UNREF(h_key);
54113 natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
54114
54115 c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
54116 c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
54117 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
54118 c_nargs = DUK_VARARGS;
54119 }
54120
54121 c_func = duk_bi_native_functions[natidx];
54122
54123 DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
54124 (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length,
54125 (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
54126
54127 /* Cast converts magic to 16-bit signed value */
54128 magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0);
54129
54130#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54131 lightfunc_eligible =
54132 ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
54133 (c_length <= DUK_LFUNC_LENGTH_MAX) &&
54134 (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
54135
54136 if (h_key == DUK_HTHREAD_STRING_EVAL(thr) ||
54137 h_key == DUK_HTHREAD_STRING_YIELD(thr) ||
54138 h_key == DUK_HTHREAD_STRING_RESUME(thr) ||
54139 h_key == DUK_HTHREAD_STRING_REQUIRE(thr)) {
54140 /* These functions have trouble working as lightfuncs.
54141 * Some of them have specific asserts and some may have
54142 * additional properties (e.g. 'require.id' may be written).
54143 */
54144 DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j));
54145 lightfunc_eligible = 0;
54146 }
54147
54148 if (lightfunc_eligible) {
54149 duk_tval tv_lfunc;
54150 duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
54151 duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
54152 DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
54153 duk_push_tval(ctx, &tv_lfunc);
54154 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)));
54155 goto lightfunc_skip;
54156 }
54157
54158 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));
54159#endif /* DUK_USE_LIGHTFUNC_BUILTINS */
54160
54161 /* [ (builtin objects) name ] */
54162
54163 duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs);
54164 h_func = duk_require_hnativefunction(ctx, -1);
54165 DUK_UNREF(h_func);
54166
54167 /* Currently all built-in native functions are strict.
54168 * This doesn't matter for many functions, but e.g.
54169 * String.prototype.charAt (and other string functions)
54170 * rely on being strict so that their 'this' binding is
54171 * not automatically coerced.
54172 */
54173 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
54174
54175 /* No built-in functions are constructable except the top
54176 * level ones (Number, etc).
54177 */
54178 DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
54179
54180 /* XXX: any way to avoid decoding magic bit; there are quite
54181 * many function properties and relatively few with magic values.
54182 */
54183 h_func->magic = magic;
54184
54185 /* [ (builtin objects) name func ] */
54186
54187 duk_push_int(ctx, c_length);
54188 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
54189
54190 duk_dup(ctx, -2);
54191 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
54192
54193 /* XXX: other properties of function instances; 'arguments', 'caller'. */
54194
54195 DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
54196 (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1)));
54197
54198 /* [ (builtin objects) name func ] */
54199
54200 /*
54201 * The default property attributes are correct for all
54202 * function valued properties of built-in objects now.
54203 */
54204
54205#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54206 lightfunc_skip:
54207#endif
54208
54209 duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC);
54210
54211 /* [ (builtin objects) ] */
54212 }
54213 }
54214
54215 /*
54216 * Special post-tweaks, for cases not covered by the init data format.
54217 *
54218 * - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
54219 * toGMTString is required to have the same Function object as
54220 * toUTCString in E5 Section B.2.6. Note that while Smjs respects
54221 * this, V8 does not (the Function objects are distinct).
54222 *
54223 * - Make DoubleError non-extensible.
54224 *
54225 * - Add info about most important effective compile options to Duktape.
54226 *
54227 * - Possibly remove some properties (values or methods) which are not
54228 * desirable with current feature options but are not currently
54229 * conditional in init data.
54230 */
54231
54232 duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
54233 duk_xdef_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
54234
54235 h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
54236 DUK_ASSERT(h != NULL);
54237 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
54238
54239#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
54240 DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
54241 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW);
54242#endif
54243
54244#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
54245 DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
54246 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW);
54247#endif
54248
54249 /* XXX: relocate */
54250 duk_push_string(ctx,
54251 /* Endianness indicator */
54252#if defined(DUK_USE_INTEGER_LE)
54253 "l"
54254#elif defined(DUK_USE_INTEGER_BE)
54255 "b"
54256#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */
54257 "m"
54258#else
54259 "?"
54260#endif
54261#if defined(DUK_USE_DOUBLE_LE)
54262 "l"
54263#elif defined(DUK_USE_DOUBLE_BE)
54264 "b"
54265#elif defined(DUK_USE_DOUBLE_ME)
54266 "m"
54267#else
54268 "?"
54269#endif
54270 " "
54271 /* Packed or unpacked tval */
54272#if defined(DUK_USE_PACKED_TVAL)
54273 "p"
54274#else
54275 "u"
54276#endif
54277#if defined(DUK_USE_FASTINT)
54278 "f"
54279#endif
54280 " "
54281 /* Low memory options */
54282#if defined(DUK_USE_STRTAB_CHAIN)
54283 "c" /* chain */
54284#elif defined(DUK_USE_STRTAB_PROBE)
54285 "p" /* probe */
54286#else
54287 "?"
54288#endif
54289#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
54290 "n"
54291#endif
54292#if defined(DUK_USE_HEAPPTR16)
54293 "h"
54294#endif
54295#if defined(DUK_USE_DATAPTR16)
54296 "d"
54297#endif
54298#if defined(DUK_USE_FUNCPTR16)
54299 "f"
54300#endif
54301#if defined(DUK_USE_REFCOUNT16)
54302 "R"
54303#endif
54304#if defined(DUK_USE_STRHASH16)
54305 "H"
54306#endif
54307#if defined(DUK_USE_STRLEN16)
54308 "S"
54309#endif
54310#if defined(DUK_USE_BUFLEN16)
54311 "B"
54312#endif
54313#if defined(DUK_USE_OBJSIZES16)
54314 "O"
54315#endif
54316#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54317 "L"
54318#endif
54319#if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
54320 /* XXX: This won't be shown in practice now
54321 * because this code is not run when builtins
54322 * are in ROM.
54323 */
54324 "Z"
54325#endif
54326 " "
54327 /* Object property allocation layout */
54328#if defined(DUK_USE_HOBJECT_LAYOUT_1)
54329 "p1"
54330#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
54331 "p2"
54332#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
54333 "p3"
54334#else
54335 "p?"
54336#endif
54337 " "
54338 /* Alignment guarantee */
54339#if (DUK_USE_ALIGN_BY == 4)
54340 "a4"
54341#elif (DUK_USE_ALIGN_BY == 8)
54342 "a8"
54343#elif (DUK_USE_ALIGN_BY == 1)
54344 "a1"
54345#else
54346#error invalid DUK_USE_ALIGN_BY
54347#endif
54348 " "
54349 /* Architecture, OS, and compiler strings */
54350 DUK_USE_ARCH_STRING
54351 " "
54352 DUK_USE_OS_STRING
54353 " "
54354 DUK_USE_COMPILER_STRING);
54355 duk_xdef_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
54356
54357 /*
54358 * InitJS code - Ecmascript code evaluated from a built-in source
54359 * which provides e.g. backward compatibility. User can also provide
54360 * JS code to be evaluated at startup.
54361 */
54362
54363#ifdef DUK_USE_BUILTIN_INITJS
54364 /* XXX: compression */
54365 DUK_DD(DUK_DDPRINT("running built-in initjs"));
54366 duk_eval_string(ctx, (const char *) duk_initjs_data); /* initjs data is NUL terminated */
54367 duk_pop(ctx);
54368#endif /* DUK_USE_BUILTIN_INITJS */
54369
54370#ifdef DUK_USE_USER_INITJS
54371 /* XXX: compression (as an option) */
54372 DUK_DD(DUK_DDPRINT("running user initjs"));
54373 duk_eval_string_noresult(ctx, (const char *) DUK_USE_USER_INITJS);
54374#endif /* DUK_USE_USER_INITJS */
54375
54376 /*
54377 * Since built-ins are not often extended, compact them.
54378 */
54379
54380 DUK_DD(DUK_DDPRINT("compact built-ins"));
54381 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
54382 duk_hobject_compact_props(thr, duk_require_hobject(ctx, i));
54383 }
54384
54385 DUK_D(DUK_DPRINT("INITBUILTINS END"));
54386
54387#ifdef DUK_USE_DDPRINT
54388 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
54389 DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
54390 (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i)));
54391 }
54392#endif
54393
54394 /*
54395 * Pop built-ins from stack: they are now INCREF'd and
54396 * reachable from the builtins[] array or indirectly
54397 * through builtins[].
54398 */
54399
54400 duk_set_top(ctx, 0);
54401 DUK_ASSERT_TOP(ctx, 0);
54402}
54403#endif /* DUK_USE_ROM_OBJECTS */
54404
54405DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
54406 duk_small_uint_t i;
54407
54408 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
54409 thr_to->builtins[i] = thr_from->builtins[i];
54410 DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
54411 }
54412}
54413#line 1 "duk_hthread_misc.c"
54414/*
54415 * Thread support.
54416 */
54417
54418/* include removed: duk_internal.h */
54419
54420DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
54421 DUK_ASSERT(thr != NULL);
54422
54423 /* Order of unwinding is important */
54424
54425 duk_hthread_catchstack_unwind(thr, 0);
54426
54427 duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */
54428
54429 thr->valstack_bottom = thr->valstack;
54430 duk_set_top((duk_context *) thr, 0); /* unwinds valstack, updating refcounts */
54431
54432 thr->state = DUK_HTHREAD_STATE_TERMINATED;
54433
54434 /* Here we could remove references to built-ins, but it may not be
54435 * worth the effort because built-ins are quite likely to be shared
54436 * with another (unterminated) thread, and terminated threads are also
54437 * usually garbage collected quite quickly. Also, doing DECREFs
54438 * could trigger finalization, which would run on the current thread
54439 * and have access to only some of the built-ins. Garbage collection
54440 * deals with this correctly already.
54441 */
54442
54443 /* XXX: Shrink the stacks to minimize memory usage? May not
54444 * be worth the effort because terminated threads are usually
54445 * garbage collected quite soon.
54446 */
54447}
54448
54449DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) {
54450 DUK_ASSERT(thr != NULL);
54451
54452 if (thr->callstack_top > 0) {
54453 return thr->callstack + thr->callstack_top - 1;
54454 } else {
54455 return NULL;
54456 }
54457}
54458
54459#if defined(DUK_USE_DEBUGGER_SUPPORT)
54460DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) {
54461 duk_instr_t *bcode;
54462
54463 DUK_ASSERT(thr != NULL);
54464 DUK_ASSERT(act != NULL);
54465 DUK_UNREF(thr);
54466
54467 /* XXX: store 'bcode' pointer to activation for faster lookup? */
54468 if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
54469 bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
54470 return (duk_uint_fast32_t) (act->curr_pc - bcode);
54471 }
54472 return 0;
54473}
54474#endif /* DUK_USE_DEBUGGER_SUPPORT */
54475
54476DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) {
54477 duk_instr_t *bcode;
54478 duk_uint_fast32_t ret;
54479
54480 DUK_ASSERT(thr != NULL);
54481 DUK_ASSERT(act != NULL);
54482 DUK_UNREF(thr);
54483
54484 if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
54485 bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
54486 ret = (duk_uint_fast32_t) (act->curr_pc - bcode);
54487 if (ret > 0) {
54488 ret--;
54489 }
54490 return ret;
54491 }
54492 return 0;
54493}
54494
54495/* Write bytecode executor's curr_pc back to topmost activation (if any). */
54496DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) {
54497 duk_activation *act;
54498
54499 DUK_ASSERT(thr != NULL);
54500
54501 if (thr->ptr_curr_pc != NULL) {
54502 /* ptr_curr_pc != NULL only when bytecode executor is active. */
54503 DUK_ASSERT(thr->callstack_top > 0);
54504 act = thr->callstack + thr->callstack_top - 1;
54505 act->curr_pc = *thr->ptr_curr_pc;
54506 }
54507}
54508
54509DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
54510 duk_activation *act;
54511
54512 DUK_ASSERT(thr != NULL);
54513
54514 if (thr->ptr_curr_pc != NULL) {
54515 /* ptr_curr_pc != NULL only when bytecode executor is active. */
54516 DUK_ASSERT(thr->callstack_top > 0);
54517 act = thr->callstack + thr->callstack_top - 1;
54518 act->curr_pc = *thr->ptr_curr_pc;
54519 thr->ptr_curr_pc = NULL;
54520 }
54521}
54522#line 1 "duk_hthread_stacks.c"
54523/*
54524 * Manipulation of thread stacks (valstack, callstack, catchstack).
54525 *
54526 * Ideally unwinding of stacks should have no side effects, which would
54527 * then favor separate unwinding and shrink check primitives for each
54528 * stack type. A shrink check may realloc and thus have side effects.
54529 *
54530 * However, currently callstack unwinding itself has side effects, as it
54531 * needs to DECREF multiple objects, close environment records, etc.
54532 * Stacks must thus be unwound in the correct order by the caller.
54533 *
54534 * (XXX: This should be probably reworked so that there is a shared
54535 * unwind primitive which handles all stacks as requested, and knows
54536 * the proper order for unwinding.)
54537 *
54538 * Valstack entries above 'top' are always kept initialized to
54539 * "undefined unused". Callstack and catchstack entries above 'top'
54540 * are not zeroed and are left as garbage.
54541 *
54542 * Value stack handling is mostly a part of the API implementation.
54543 */
54544
54545/* include removed: duk_internal.h */
54546
54547/* check that there is space for at least one new entry */
54548DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) {
54549 duk_activation *new_ptr;
54550 duk_size_t old_size;
54551 duk_size_t new_size;
54552
54553 DUK_ASSERT(thr != NULL);
54554 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
54555 DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
54556
54557 if (thr->callstack_top < thr->callstack_size) {
54558 return;
54559 }
54560
54561 old_size = thr->callstack_size;
54562 new_size = old_size + DUK_CALLSTACK_GROW_STEP;
54563
54564 /* this is a bit approximate (errors out before max is reached); this is OK */
54565 if (new_size >= thr->callstack_max) {
54566 DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
54567 }
54568
54569 DUK_DD(DUK_DDPRINT("growing callstack %ld -> %ld", (long) old_size, (long) new_size));
54570
54571 /*
54572 * Note: must use indirect variant of DUK_REALLOC() because underlying
54573 * pointer may be changed by mark-and-sweep.
54574 */
54575
54576 DUK_ASSERT(new_size > 0);
54577 new_ptr = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
54578 if (!new_ptr) {
54579 /* No need for a NULL/zero-size check because new_size > 0) */
54580 DUK_ERROR_ALLOC_DEFMSG(thr);
54581 }
54582 thr->callstack = new_ptr;
54583 thr->callstack_size = new_size;
54584
54585 /* note: any entries above the callstack top are garbage and not zeroed */
54586}
54587
54588DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
54589 duk_size_t new_size;
54590 duk_activation *p;
54591
54592 DUK_ASSERT(thr != NULL);
54593 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
54594 DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
54595
54596 if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) {
54597 return;
54598 }
54599
54600 new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
54601 DUK_ASSERT(new_size >= thr->callstack_top);
54602
54603 DUK_DD(DUK_DDPRINT("shrinking callstack %ld -> %ld", (long) thr->callstack_size, (long) new_size));
54604
54605 /*
54606 * Note: must use indirect variant of DUK_REALLOC() because underlying
54607 * pointer may be changed by mark-and-sweep.
54608 */
54609
54610 /* shrink failure is not fatal */
54611 p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
54612 if (p) {
54613 thr->callstack = p;
54614 thr->callstack_size = new_size;
54615 } else {
54616 /* Because new_size != 0, if condition doesn't need to be
54617 * (p != NULL || new_size == 0).
54618 */
54619 DUK_ASSERT(new_size != 0);
54620 DUK_D(DUK_DPRINT("callstack shrink failed, ignoring"));
54621 }
54622
54623 /* note: any entries above the callstack top are garbage and not zeroed */
54624}
54625
54626DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) {
54627 duk_size_t idx;
54628
54629 DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld",
54630 (void *) thr,
54631 (thr != NULL ? (long) thr->callstack_top : (long) -1),
54632 (long) new_top));
54633
54634 DUK_ASSERT(thr);
54635 DUK_ASSERT(thr->heap);
54636 DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
54637 DUK_ASSERT((duk_size_t) new_top <= thr->callstack_top); /* cannot grow */
54638
54639 /*
54640 * The loop below must avoid issues with potential callstack
54641 * reallocations. A resize (and other side effects) may happen
54642 * e.g. due to finalizer/errhandler calls caused by a refzero or
54643 * mark-and-sweep. Arbitrary finalizers may run, because when
54644 * an environment record is refzero'd, it may refer to arbitrary
54645 * values which also become refzero'd.
54646 *
54647 * So, the pointer 'p' is re-looked-up below whenever a side effect
54648 * might have changed it.
54649 */
54650
54651 idx = thr->callstack_top;
54652 while (idx > new_top) {
54653 duk_activation *act;
54654 duk_hobject *func;
54655#ifdef DUK_USE_REFERENCE_COUNTING
54656 duk_hobject *tmp;
54657#endif
54658#ifdef DUK_USE_DEBUGGER_SUPPORT
54659 duk_heap *heap;
54660#endif
54661
54662 idx--;
54663 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
54664 DUK_ASSERT((duk_size_t) idx < thr->callstack_size); /* true, despite side effect resizes */
54665
54666 act = thr->callstack + idx;
54667 /* With lightfuncs, act 'func' may be NULL */
54668
54669#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
54670 /*
54671 * Restore 'caller' property for non-strict callee functions.
54672 */
54673
54674 func = DUK_ACT_GET_FUNC(act);
54675 if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
54676 duk_tval *tv_caller;
54677 duk_tval tv_tmp;
54678 duk_hobject *h_tmp;
54679
54680 tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
54681
54682 /* The act->prev_caller should only be set if the entry for 'caller'
54683 * exists (as it is only set in that case, and the property is not
54684 * configurable), but handle all the cases anyway.
54685 */
54686
54687 if (tv_caller) {
54688 DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
54689 if (act->prev_caller) {
54690 /* Just transfer the refcount from act->prev_caller to tv_caller,
54691 * so no need for a refcount update. This is the expected case.
54692 */
54693 DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
54694 act->prev_caller = NULL;
54695 } else {
54696 DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
54697 DUK_ASSERT(act->prev_caller == NULL);
54698 }
54699 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
54700 } else {
54701 h_tmp = act->prev_caller;
54702 if (h_tmp) {
54703 act->prev_caller = NULL;
54704 DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */
54705 }
54706 }
54707 act = thr->callstack + idx; /* avoid side effects */
54708 DUK_ASSERT(act->prev_caller == NULL);
54709 }
54710#endif
54711
54712 /*
54713 * Unwind debugger state. If we unwind while stepping
54714 * (either step over or step into), pause execution.
54715 */
54716
54717#if defined(DUK_USE_DEBUGGER_SUPPORT)
54718 heap = thr->heap;
54719 if (heap->dbg_step_thread == thr &&
54720 heap->dbg_step_csindex == idx) {
54721 /* Pause for all step types: step into, step over, step out.
54722 * This is the only place explicitly handling a step out.
54723 */
54724 DUK_HEAP_SET_PAUSED(heap);
54725 DUK_ASSERT(heap->dbg_step_thread == NULL);
54726 }
54727#endif
54728
54729 /*
54730 * Close environment record(s) if they exist.
54731 *
54732 * Only variable environments are closed. If lex_env != var_env, it
54733 * cannot currently contain any register bound declarations.
54734 *
54735 * Only environments created for a NEWENV function are closed. If an
54736 * environment is created for e.g. an eval call, it must not be closed.
54737 */
54738
54739 func = DUK_ACT_GET_FUNC(act);
54740 if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
54741 DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
54742 goto skip_env_close;
54743 }
54744 /* func is NULL for lightfunc */
54745
54746 DUK_ASSERT(act->lex_env == act->var_env);
54747 if (act->var_env != NULL) {
54748 DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
54749 (void *) act->var_env, (duk_heaphdr *) act->var_env));
54750 duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom);
54751 act = thr->callstack + idx; /* avoid side effect issues */
54752 }
54753
54754#if 0
54755 if (act->lex_env != NULL) {
54756 if (act->lex_env == act->var_env) {
54757 /* common case, already closed, so skip */
54758 DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env "
54759 "already closed -> skip closing lex_env"));
54760 ;
54761 } else {
54762 DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O",
54763 (void *) act->lex_env, (duk_heaphdr *) act->lex_env));
54764 duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom);
54765 act = thr->callstack + idx; /* avoid side effect issues */
54766 }
54767 }
54768#endif
54769
54770 DUK_ASSERT((act->lex_env == NULL) ||
54771 ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
54772 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
54773 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
54774 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
54775
54776 DUK_ASSERT((act->var_env == NULL) ||
54777 ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
54778 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
54779 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
54780 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
54781
54782 skip_env_close:
54783
54784 /*
54785 * Update preventcount
54786 */
54787
54788 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
54789 DUK_ASSERT(thr->callstack_preventcount >= 1);
54790 thr->callstack_preventcount--;
54791 }
54792
54793 /*
54794 * Reference count updates
54795 *
54796 * Note: careful manipulation of refcounts. The top is
54797 * not updated yet, so all the activations are reachable
54798 * for mark-and-sweep (which may be triggered by decref).
54799 * However, the pointers are NULL so this is not an issue.
54800 */
54801
54802#ifdef DUK_USE_REFERENCE_COUNTING
54803 tmp = act->var_env;
54804#endif
54805 act->var_env = NULL;
54806#ifdef DUK_USE_REFERENCE_COUNTING
54807 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
54808 act = thr->callstack + idx; /* avoid side effect issues */
54809#endif
54810
54811#ifdef DUK_USE_REFERENCE_COUNTING
54812 tmp = act->lex_env;
54813#endif
54814 act->lex_env = NULL;
54815#ifdef DUK_USE_REFERENCE_COUNTING
54816 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
54817 act = thr->callstack + idx; /* avoid side effect issues */
54818#endif
54819
54820 /* Note: this may cause a corner case situation where a finalizer
54821 * may see a currently reachable activation whose 'func' is NULL.
54822 */
54823#ifdef DUK_USE_REFERENCE_COUNTING
54824 tmp = DUK_ACT_GET_FUNC(act);
54825#endif
54826 act->func = NULL;
54827#ifdef DUK_USE_REFERENCE_COUNTING
54828 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
54829 act = thr->callstack + idx; /* avoid side effect issues */
54830 DUK_UNREF(act);
54831#endif
54832 }
54833
54834 thr->callstack_top = new_top;
54835
54836 /*
54837 * We could clear the book-keeping variables for the topmost activation,
54838 * but don't do so now.
54839 */
54840#if 0
54841 if (thr->callstack_top > 0) {
54842 duk_activation *act = thr->callstack + thr->callstack_top - 1;
54843 act->idx_retval = 0;
54844 }
54845#endif
54846
54847 /* Note: any entries above the callstack top are garbage and not zeroed.
54848 * Also topmost activation idx_retval is garbage (not zeroed), and must
54849 * be ignored.
54850 */
54851}
54852
54853DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) {
54854 duk_catcher *new_ptr;
54855 duk_size_t old_size;
54856 duk_size_t new_size;
54857
54858 DUK_ASSERT(thr != NULL);
54859 DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */
54860 DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
54861
54862 if (thr->catchstack_top < thr->catchstack_size) {
54863 return;
54864 }
54865
54866 old_size = thr->catchstack_size;
54867 new_size = old_size + DUK_CATCHSTACK_GROW_STEP;
54868
54869 /* this is a bit approximate (errors out before max is reached); this is OK */
54870 if (new_size >= thr->catchstack_max) {
54871 DUK_ERROR_RANGE(thr, DUK_STR_CATCHSTACK_LIMIT);
54872 }
54873
54874 DUK_DD(DUK_DDPRINT("growing catchstack %ld -> %ld", (long) old_size, (long) new_size));
54875
54876 /*
54877 * Note: must use indirect variant of DUK_REALLOC() because underlying
54878 * pointer may be changed by mark-and-sweep.
54879 */
54880
54881 DUK_ASSERT(new_size > 0);
54882 new_ptr = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
54883 if (!new_ptr) {
54884 /* No need for a NULL/zero-size check because new_size > 0) */
54885 DUK_ERROR_ALLOC_DEFMSG(thr);
54886 }
54887 thr->catchstack = new_ptr;
54888 thr->catchstack_size = new_size;
54889
54890 /* note: any entries above the catchstack top are garbage and not zeroed */
54891}
54892
54893DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
54894 duk_size_t new_size;
54895 duk_catcher *p;
54896
54897 DUK_ASSERT(thr != NULL);
54898 DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */
54899 DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
54900
54901 if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) {
54902 return;
54903 }
54904
54905 new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
54906 DUK_ASSERT(new_size >= thr->catchstack_top);
54907
54908 DUK_DD(DUK_DDPRINT("shrinking catchstack %ld -> %ld", (long) thr->catchstack_size, (long) new_size));
54909
54910 /*
54911 * Note: must use indirect variant of DUK_REALLOC() because underlying
54912 * pointer may be changed by mark-and-sweep.
54913 */
54914
54915 /* shrink failure is not fatal */
54916 p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
54917 if (p) {
54918 thr->catchstack = p;
54919 thr->catchstack_size = new_size;
54920 } else {
54921 /* Because new_size != 0, if condition doesn't need to be
54922 * (p != NULL || new_size == 0).
54923 */
54924 DUK_ASSERT(new_size != 0);
54925 DUK_D(DUK_DPRINT("catchstack shrink failed, ignoring"));
54926 }
54927
54928 /* note: any entries above the catchstack top are garbage and not zeroed */
54929}
54930
54931DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) {
54932 duk_size_t idx;
54933
54934 DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld",
54935 (void *) thr,
54936 (thr != NULL ? (long) thr->catchstack_top : (long) -1),
54937 (long) new_top));
54938
54939 DUK_ASSERT(thr);
54940 DUK_ASSERT(thr->heap);
54941 DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
54942 DUK_ASSERT((duk_size_t) new_top <= thr->catchstack_top); /* cannot grow */
54943
54944 /*
54945 * Since there are no references in the catcher structure,
54946 * unwinding is quite simple. The only thing we need to
54947 * look out for is popping a possible lexical environment
54948 * established for an active catch clause.
54949 */
54950
54951 idx = thr->catchstack_top;
54952 while (idx > new_top) {
54953 duk_catcher *p;
54954 duk_activation *act;
54955 duk_hobject *env;
54956
54957 idx--;
54958 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
54959 DUK_ASSERT((duk_size_t) idx < thr->catchstack_size);
54960
54961 p = thr->catchstack + idx;
54962
54963 if (DUK_CAT_HAS_LEXENV_ACTIVE(p)) {
54964 DUK_DDD(DUK_DDDPRINT("unwinding catchstack idx %ld, callstack idx %ld, callstack top %ld: lexical environment active",
54965 (long) idx, (long) p->callstack_index, (long) thr->callstack_top));
54966
54967 /* XXX: Here we have a nasty dependency: the need to manipulate
54968 * the callstack means that catchstack must always be unwound by
54969 * the caller before unwinding the callstack. This should be fixed
54970 * later.
54971 */
54972
54973 /* Note that multiple catchstack entries may refer to the same
54974 * callstack entry.
54975 */
54976 act = thr->callstack + p->callstack_index;
54977 DUK_ASSERT(act >= thr->callstack);
54978 DUK_ASSERT(act < thr->callstack + thr->callstack_top);
54979
54980 DUK_DDD(DUK_DDDPRINT("catchstack_index=%ld, callstack_index=%ld, lex_env=%!iO",
54981 (long) idx, (long) p->callstack_index,
54982 (duk_heaphdr *) act->lex_env));
54983
54984 env = act->lex_env; /* current lex_env of the activation (created for catcher) */
54985 DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
54986 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
54987 DUK_HOBJECT_DECREF(thr, env);
54988
54989 /* There is no need to decref anything else than 'env': if 'env'
54990 * becomes unreachable, refzero will handle decref'ing its prototype.
54991 */
54992 }
54993 }
54994
54995 thr->catchstack_top = new_top;
54996
54997 /* note: any entries above the catchstack top are garbage and not zeroed */
54998}
54999#line 1 "duk_js_call.c"
55000/*
55001 * Call handling.
55002 *
55003 * Main functions are:
55004 *
55005 * - duk_handle_call_unprotected(): unprotected call to Ecmascript or
55006 * Duktape/C function
55007 * - duk_handle_call_protected(): protected call to Ecmascript or
55008 * Duktape/C function
55009 * - duk_handle_safe_call(): make a protected C call within current
55010 * activation
55011 * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls
55012 * (not always possible), including tail calls and coroutine resume
55013 *
55014 * See 'execution.rst'.
55015 *
55016 * Note: setjmp() and local variables have a nasty interaction,
55017 * see execution.rst; non-volatile locals modified after setjmp()
55018 * call are not guaranteed to keep their value.
55019 */
55020
55021/* include removed: duk_internal.h */
55022
55023/*
55024 * Forward declarations.
55025 */
55026
55027DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
55028 duk_idx_t num_stack_args,
55029 duk_small_uint_t call_flags,
55030 duk_idx_t idx_func);
55031DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
55032 duk_size_t entry_valstack_bottom_index,
55033 duk_size_t entry_valstack_end,
55034 duk_size_t entry_catchstack_top,
55035 duk_size_t entry_callstack_top,
55036 duk_int_t entry_call_recursion_depth,
55037 duk_hthread *entry_curr_thread,
55038 duk_uint_fast8_t entry_thread_state,
55039 duk_instr_t **entry_ptr_curr_pc,
55040 duk_idx_t idx_func,
55041 duk_jmpbuf *old_jmpbuf_ptr);
55042DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
55043 duk_safe_call_function func,
55044 duk_idx_t idx_retbase,
55045 duk_idx_t num_stack_rets,
55046 duk_size_t entry_valstack_bottom_index,
55047 duk_size_t entry_callstack_top,
55048 duk_size_t entry_catchstack_top);
55049DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
55050 duk_idx_t idx_retbase,
55051 duk_idx_t num_stack_rets,
55052 duk_size_t entry_valstack_bottom_index,
55053 duk_size_t entry_callstack_top,
55054 duk_size_t entry_catchstack_top,
55055 duk_jmpbuf *old_jmpbuf_ptr);
55056DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
55057 duk_idx_t idx_retbase,
55058 duk_idx_t num_stack_rets,
55059 duk_int_t entry_call_recursion_depth,
55060 duk_hthread *entry_curr_thread,
55061 duk_uint_fast8_t entry_thread_state,
55062 duk_instr_t **entry_ptr_curr_pc);
55063
55064/*
55065 * Interrupt counter fixup (for development only).
55066 */
55067
55068#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
55069DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
55070 /* Currently the bytecode executor and executor interrupt
55071 * instruction counts are off because we don't execute the
55072 * interrupt handler when we're about to exit from the initial
55073 * user call into Duktape.
55074 *
55075 * If we were to execute the interrupt handler here, the counts
55076 * would match. You can enable this block manually to check
55077 * that this is the case.
55078 */
55079
55080 DUK_ASSERT(thr != NULL);
55081 DUK_ASSERT(thr->heap != NULL);
55082
55083#if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP)
55084 if (entry_curr_thread == NULL) {
55085 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
55086 thr->heap->inst_count_interrupt += thr->interrupt_init;
55087 DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to "
55088 "user code, instruction counts: executor=%ld, interrupt=%ld",
55089 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
55090 DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt);
55091 }
55092#else
55093 DUK_UNREF(thr);
55094 DUK_UNREF(entry_curr_thread);
55095#endif
55096}
55097#endif
55098
55099/*
55100 * Arguments object creation.
55101 *
55102 * Creating arguments objects involves many small details, see E5 Section
55103 * 10.6 for the specific requirements. Much of the arguments object exotic
55104 * behavior is implemented in duk_hobject_props.c, and is enabled by the
55105 * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
55106 */
55107
55108DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
55109 duk_hobject *func,
55110 duk_hobject *varenv,
55111 duk_idx_t idx_argbase, /* idx of first argument on stack */
55112 duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
55113 duk_context *ctx = (duk_context *) thr;
55114 duk_hobject *arg; /* 'arguments' */
55115 duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
55116 duk_idx_t i_arg;
55117 duk_idx_t i_map;
55118 duk_idx_t i_mappednames;
55119 duk_idx_t i_formals;
55120 duk_idx_t i_argbase;
55121 duk_idx_t n_formals;
55122 duk_idx_t idx;
55123 duk_bool_t need_map;
55124
55125 DUK_DDD(DUK_DDDPRINT("creating arguments object for func=%!iO, varenv=%!iO, "
55126 "idx_argbase=%ld, num_stack_args=%ld",
55127 (duk_heaphdr *) func, (duk_heaphdr *) varenv,
55128 (long) idx_argbase, (long) num_stack_args));
55129
55130 DUK_ASSERT(thr != NULL);
55131 DUK_ASSERT(func != NULL);
55132 DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
55133 DUK_ASSERT(varenv != NULL);
55134 DUK_ASSERT(idx_argbase >= 0); /* assumed to bottom relative */
55135 DUK_ASSERT(num_stack_args >= 0);
55136
55137 need_map = 0;
55138
55139 i_argbase = idx_argbase;
55140 DUK_ASSERT(i_argbase >= 0);
55141
55142 duk_push_hobject(ctx, func);
55143 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FORMALS);
55144 formals = duk_get_hobject(ctx, -1);
55145 n_formals = 0;
55146 if (formals) {
55147 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
55148 n_formals = (duk_idx_t) duk_require_int(ctx, -1);
55149 duk_pop(ctx);
55150 }
55151 duk_remove(ctx, -2); /* leave formals on stack for later use */
55152 i_formals = duk_require_top_index(ctx);
55153
55154 DUK_ASSERT(n_formals >= 0);
55155 DUK_ASSERT(formals != NULL || n_formals == 0);
55156
55157 DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld",
55158 (duk_heaphdr *) func, (duk_heaphdr *) formals,
55159 (long) n_formals));
55160
55161 /* [ ... formals ] */
55162
55163 /*
55164 * Create required objects:
55165 * - 'arguments' object: array-like, but not an array
55166 * - 'map' object: internal object, tied to 'arguments'
55167 * - 'mappedNames' object: temporary value used during construction
55168 */
55169
55170 i_arg = duk_push_object_helper(ctx,
55171 DUK_HOBJECT_FLAG_EXTENSIBLE |
55172 DUK_HOBJECT_FLAG_ARRAY_PART |
55173 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
55174 DUK_BIDX_OBJECT_PROTOTYPE);
55175 DUK_ASSERT(i_arg >= 0);
55176 arg = duk_require_hobject(ctx, -1);
55177 DUK_ASSERT(arg != NULL);
55178
55179 i_map = duk_push_object_helper(ctx,
55180 DUK_HOBJECT_FLAG_EXTENSIBLE |
55181 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
55182 -1); /* no prototype */
55183 DUK_ASSERT(i_map >= 0);
55184
55185 i_mappednames = duk_push_object_helper(ctx,
55186 DUK_HOBJECT_FLAG_EXTENSIBLE |
55187 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
55188 -1); /* no prototype */
55189 DUK_ASSERT(i_mappednames >= 0);
55190
55191 /* [ ... formals arguments map mappedNames ] */
55192
55193 DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
55194 "arguments at index %ld -> %!O "
55195 "map at index %ld -> %!O "
55196 "mappednames at index %ld -> %!O",
55197 (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
55198 (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
55199 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
55200
55201 /*
55202 * Init arguments properties, map, etc.
55203 */
55204
55205 duk_push_int(ctx, num_stack_args);
55206 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
55207
55208 /*
55209 * Init argument related properties
55210 */
55211
55212 /* step 11 */
55213 idx = num_stack_args - 1;
55214 while (idx >= 0) {
55215 DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld",
55216 (long) idx, (long) i_argbase, (long) (i_argbase + idx)));
55217
55218 DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
55219 duk_dup(ctx, i_argbase + idx);
55220 duk_xdef_prop_index_wec(ctx, i_arg, (duk_uarridx_t) idx);
55221 DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
55222
55223 /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
55224 if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) {
55225 DUK_ASSERT(formals != NULL);
55226
55227 DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
55228 (long) idx, (long) n_formals));
55229
55230 duk_get_prop_index(ctx, i_formals, idx);
55231 DUK_ASSERT(duk_is_string(ctx, -1));
55232
55233 duk_dup(ctx, -1); /* [ ... name name ] */
55234
55235 if (!duk_has_prop(ctx, i_mappednames)) {
55236 /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
55237 * differs from the reference model
55238 */
55239
55240 /* [ ... name ] */
55241
55242 need_map = 1;
55243
55244 DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
55245 (const char *) duk_get_string(ctx, -1),
55246 (long) idx));
55247 duk_dup(ctx, -1); /* name */
55248 duk_push_uint(ctx, (duk_uint_t) idx); /* index */
55249 duk_to_string(ctx, -1);
55250 duk_xdef_prop_wec(ctx, i_mappednames); /* out of spec, must be configurable */
55251
55252 DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
55253 (long) idx,
55254 duk_get_string(ctx, -1)));
55255 duk_dup(ctx, -1); /* name */
55256 duk_xdef_prop_index_wec(ctx, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
55257 } else {
55258 /* duk_has_prop() popped the second 'name' */
55259 }
55260
55261 /* [ ... name ] */
55262 duk_pop(ctx); /* pop 'name' */
55263 }
55264
55265 idx--;
55266 }
55267
55268 DUK_DDD(DUK_DDDPRINT("actual arguments processed"));
55269
55270 /* step 12 */
55271 if (need_map) {
55272 DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object"));
55273
55274 /* should never happen for a strict callee */
55275 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
55276
55277 duk_dup(ctx, i_map);
55278 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
55279
55280 /* The variable environment for magic variable bindings needs to be
55281 * given by the caller and recorded in the arguments object.
55282 *
55283 * See E5 Section 10.6, the creation of setters/getters.
55284 *
55285 * The variable environment also provides access to the callee, so
55286 * an explicit (internal) callee property is not needed.
55287 */
55288
55289 duk_push_hobject(ctx, varenv);
55290 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
55291 }
55292
55293 /* steps 13-14 */
55294 if (DUK_HOBJECT_HAS_STRICT(func)) {
55295 /* Callee/caller are throwers and are not deletable etc. They
55296 * could be implemented as virtual properties, but currently
55297 * there is no support for virtual properties which are accessors
55298 * (only plain virtual properties). This would not be difficult
55299 * to change in duk_hobject_props, but we can make the throwers
55300 * normal, concrete properties just as easily.
55301 *
55302 * Note that the specification requires that the *same* thrower
55303 * built-in object is used here! See E5 Section 10.6 main
55304 * algoritm, step 14, and Section 13.2.3 which describes the
55305 * thrower. See test case test-arguments-throwers.js.
55306 */
55307
55308 DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
55309
55310 duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
55311 duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_NONE);
55312 } else {
55313 DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
55314 duk_push_hobject(ctx, func);
55315 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
55316 }
55317
55318 /* set exotic behavior only after we're done */
55319 if (need_map) {
55320 /* Exotic behaviors are only enabled for arguments objects
55321 * which have a parameter map (see E5 Section 10.6 main
55322 * algorithm, step 12).
55323 *
55324 * In particular, a non-strict arguments object with no
55325 * mapped formals does *NOT* get exotic behavior, even
55326 * for e.g. "caller" property. This seems counterintuitive
55327 * but seems to be the case.
55328 */
55329
55330 /* cannot be strict (never mapped variables) */
55331 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
55332
55333 DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object"));
55334 DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg);
55335 } else {
55336 DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
55337 }
55338
55339 DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
55340 "arguments at index %ld -> %!O "
55341 "map at index %ld -> %!O "
55342 "mappednames at index %ld -> %!O",
55343 (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
55344 (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
55345 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
55346
55347 /* [ args(n) [crud] formals arguments map mappednames ] */
55348
55349 duk_pop_2(ctx);
55350 duk_remove(ctx, -2);
55351
55352 /* [ args [crud] arguments ] */
55353}
55354
55355/* Helper for creating the arguments object and adding it to the env record
55356 * on top of the value stack. This helper has a very strict dependency on
55357 * the shape of the input stack.
55358 */
55359DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
55360 duk_hobject *func,
55361 duk_hobject *env,
55362 duk_idx_t num_stack_args) {
55363 duk_context *ctx = (duk_context *) thr;
55364
55365 DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
55366
55367 DUK_ASSERT(thr != NULL);
55368 DUK_ASSERT(func != NULL);
55369 DUK_ASSERT(env != NULL);
55370 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
55371 DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
55372
55373 /* [ ... arg1 ... argN envobj ] */
55374
55375 duk__create_arguments_object(thr,
55376 func,
55377 env,
55378 duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
55379 num_stack_args);
55380
55381 /* [ ... arg1 ... argN envobj argobj ] */
55382
55383 duk_xdef_prop_stridx(ctx,
55384 -2,
55385 DUK_STRIDX_LC_ARGUMENTS,
55386 DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
55387 DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
55388 /* [ ... arg1 ... argN envobj ] */
55389}
55390
55391/*
55392 * Helper for handling a "bound function" chain when a call is being made.
55393 *
55394 * Follows the bound function chain until a non-bound function is found.
55395 * Prepends the bound arguments to the value stack (at idx_func + 2),
55396 * updating 'num_stack_args' in the process. The 'this' binding is also
55397 * updated if necessary (at idx_func + 1). Note that for constructor calls
55398 * the 'this' binding is never updated by [[BoundThis]].
55399 *
55400 * XXX: bound function chains could be collapsed at bound function creation
55401 * time so that each bound function would point directly to a non-bound
55402 * function. This would make call time handling much easier.
55403 */
55404
55405DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
55406 duk_idx_t idx_func,
55407 duk_idx_t *p_num_stack_args, /* may be changed by call */
55408 duk_bool_t is_constructor_call) {
55409 duk_context *ctx = (duk_context *) thr;
55410 duk_idx_t num_stack_args;
55411 duk_tval *tv_func;
55412 duk_hobject *func;
55413 duk_uint_t sanity;
55414
55415 DUK_ASSERT(thr != NULL);
55416 DUK_ASSERT(p_num_stack_args != NULL);
55417
55418 /* On entry, item at idx_func is a bound, non-lightweight function,
55419 * but we don't rely on that below.
55420 */
55421
55422 num_stack_args = *p_num_stack_args;
55423
55424 sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
55425 do {
55426 duk_idx_t i, len;
55427
55428 tv_func = duk_require_tval(ctx, idx_func);
55429 DUK_ASSERT(tv_func != NULL);
55430
55431 if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
55432 /* Lightweight function: never bound, so terminate. */
55433 break;
55434 } else if (DUK_TVAL_IS_OBJECT(tv_func)) {
55435 func = DUK_TVAL_GET_OBJECT(tv_func);
55436 if (!DUK_HOBJECT_HAS_BOUND(func)) {
55437 /* Normal non-bound function. */
55438 break;
55439 }
55440 } else {
55441 /* Function.prototype.bind() should never let this happen,
55442 * ugly error message is enough.
55443 */
55444 DUK_ERROR_INTERNAL_DEFMSG(thr);
55445 }
55446 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv_func) != NULL);
55447
55448 /* XXX: this could be more compact by accessing the internal properties
55449 * directly as own properties (they cannot be inherited, and are not
55450 * externally visible).
55451 */
55452
55453 DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p, num_stack_args=%ld: %!T",
55454 (void *) DUK_TVAL_GET_OBJECT(tv_func), (long) num_stack_args, tv_func));
55455
55456 /* [ ... func this arg1 ... argN ] */
55457
55458 if (is_constructor_call) {
55459 /* See: tests/ecmascript/test-spec-bound-constructor.js */
55460 DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
55461 } else {
55462 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_THIS);
55463 duk_replace(ctx, idx_func + 1); /* idx_this = idx_func + 1 */
55464 }
55465
55466 /* [ ... func this arg1 ... argN ] */
55467
55468 /* XXX: duk_get_length? */
55469 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_ARGS); /* -> [ ... func this arg1 ... argN _Args ] */
55470 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */
55471 len = (duk_idx_t) duk_require_int(ctx, -1);
55472 duk_pop(ctx);
55473
55474 duk_require_stack(ctx, len);
55475 for (i = 0; i < len; i++) {
55476 /* XXX: very slow - better to bulk allocate a gap, and copy
55477 * from args_array directly (we know it has a compact array
55478 * part, etc).
55479 */
55480
55481 /* [ ... func this <some bound args> arg1 ... argN _Args ] */
55482 duk_get_prop_index(ctx, -1, i);
55483 duk_insert(ctx, idx_func + 2 + i); /* idx_args = idx_func + 2 */
55484 }
55485 num_stack_args += len; /* must be updated to work properly (e.g. creation of 'arguments') */
55486 duk_pop(ctx);
55487
55488 /* [ ... func this <bound args> arg1 ... argN ] */
55489
55490 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_TARGET);
55491 duk_replace(ctx, idx_func); /* replace in stack */
55492
55493 DUK_DDD(DUK_DDDPRINT("bound function handled, num_stack_args=%ld, idx_func=%ld, curr func=%!T",
55494 (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func)));
55495 } while (--sanity > 0);
55496
55497 if (sanity == 0) {
55498 DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
55499 }
55500
55501 DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
55502
55503#if defined(DUK_USE_ASSERTIONS)
55504 tv_func = duk_require_tval(ctx, idx_func);
55505 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
55506 if (DUK_TVAL_IS_OBJECT(tv_func)) {
55507 func = DUK_TVAL_GET_OBJECT(tv_func);
55508 DUK_ASSERT(func != NULL);
55509 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
55510 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func) ||
55511 DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
55512 }
55513#endif
55514
55515 /* write back */
55516 *p_num_stack_args = num_stack_args;
55517}
55518
55519/*
55520 * Helper for setting up var_env and lex_env of an activation,
55521 * assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
55522 */
55523
55524DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
55525 duk_hobject *func,
55526 duk_activation *act) {
55527 duk_tval *tv;
55528
55529 DUK_ASSERT(thr != NULL);
55530 DUK_ASSERT(func != NULL);
55531 DUK_ASSERT(act != NULL);
55532 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
55533 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
55534
55535 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
55536 if (tv) {
55537 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
55538 DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
55539 act->lex_env = DUK_TVAL_GET_OBJECT(tv);
55540
55541 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr));
55542 if (tv) {
55543 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
55544 DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
55545 act->var_env = DUK_TVAL_GET_OBJECT(tv);
55546 } else {
55547 act->var_env = act->lex_env;
55548 }
55549 } else {
55550 act->lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
55551 act->var_env = act->lex_env;
55552 }
55553
55554 DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->lex_env);
55555 DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->var_env);
55556}
55557
55558/*
55559 * Helper for updating callee 'caller' property.
55560 */
55561
55562#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
55563DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
55564 duk_tval *tv_caller;
55565 duk_hobject *h_tmp;
55566 duk_activation *act_callee;
55567 duk_activation *act_caller;
55568
55569 DUK_ASSERT(thr != NULL);
55570 DUK_ASSERT(func != NULL);
55571 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound chain resolved */
55572 DUK_ASSERT(thr->callstack_top >= 1);
55573
55574 if (DUK_HOBJECT_HAS_STRICT(func)) {
55575 /* Strict functions don't get their 'caller' updated. */
55576 return;
55577 }
55578
55579 act_callee = thr->callstack + thr->callstack_top - 1;
55580 act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
55581
55582 /* XXX: check .caller writability? */
55583
55584 /* Backup 'caller' property and update its value. */
55585 tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
55586 if (tv_caller) {
55587 /* If caller is global/eval code, 'caller' should be set to
55588 * 'null'.
55589 *
55590 * XXX: there is no exotic flag to infer this correctly now.
55591 * The NEWENV flag is used now which works as intended for
55592 * everything (global code, non-strict eval code, and functions)
55593 * except strict eval code. Bound functions are never an issue
55594 * because 'func' has been resolved to a non-bound function.
55595 */
55596
55597 if (act_caller) {
55598 /* act_caller->func may be NULL in some finalization cases,
55599 * just treat like we don't know the caller.
55600 */
55601 if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) {
55602 /* Setting to NULL causes 'caller' to be set to
55603 * 'null' as desired.
55604 */
55605 act_caller = NULL;
55606 }
55607 }
55608
55609 if (DUK_TVAL_IS_OBJECT(tv_caller)) {
55610 h_tmp = DUK_TVAL_GET_OBJECT(tv_caller);
55611 DUK_ASSERT(h_tmp != NULL);
55612 act_callee->prev_caller = h_tmp;
55613
55614 /* Previous value doesn't need refcount changes because its ownership
55615 * is transferred to prev_caller.
55616 */
55617
55618 if (act_caller) {
55619 DUK_ASSERT(act_caller->func != NULL);
55620 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
55621 DUK_TVAL_INCREF(thr, tv_caller);
55622 } else {
55623 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
55624 }
55625 } else {
55626 /* 'caller' must only take on 'null' or function value */
55627 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
55628 DUK_ASSERT(act_callee->prev_caller == NULL);
55629 if (act_caller && act_caller->func) {
55630 /* Tolerate act_caller->func == NULL which happens in
55631 * some finalization cases; treat like unknown caller.
55632 */
55633 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
55634 DUK_TVAL_INCREF(thr, tv_caller);
55635 } else {
55636 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
55637 }
55638 }
55639 }
55640}
55641#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
55642
55643/*
55644 * Determine the effective 'this' binding and coerce the current value
55645 * on the valstack to the effective one (in-place, at idx_this).
55646 *
55647 * The current this value in the valstack (at idx_this) represents either:
55648 * - the caller's requested 'this' binding; or
55649 * - a 'this' binding accumulated from the bound function chain
55650 *
55651 * The final 'this' binding for the target function may still be
55652 * different, and is determined as described in E5 Section 10.4.3.
55653 *
55654 * For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
55655 * that the caller has provided the correct 'this' binding explicitly
55656 * when calling, i.e.:
55657 *
55658 * - global code: this=global object
55659 * - direct eval: this=copy from eval() caller's this binding
55660 * - other eval: this=global object
55661 *
55662 * Note: this function may cause a recursive function call with arbitrary
55663 * side effects, because ToObject() may be called.
55664 */
55665
55666DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
55667 duk_hobject *func,
55668 duk_idx_t idx_this) {
55669 duk_context *ctx = (duk_context *) thr;
55670 duk_tval *tv_this;
55671 duk_hobject *obj_global;
55672
55673 if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
55674 /* Lightfuncs are always considered strict. */
55675 DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
55676 return;
55677 }
55678
55679 /* XXX: byte offset */
55680 tv_this = thr->valstack_bottom + idx_this;
55681 switch (DUK_TVAL_GET_TAG(tv_this)) {
55682 case DUK_TAG_OBJECT:
55683 case DUK_TAG_LIGHTFUNC: /* lightfuncs are treated like objects and not coerced */
55684 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
55685 break;
55686 case DUK_TAG_UNDEFINED:
55687 case DUK_TAG_NULL:
55688 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
55689 obj_global = thr->builtins[DUK_BIDX_GLOBAL];
55690 /* XXX: avoid this check somehow */
55691 if (DUK_LIKELY(obj_global != NULL)) {
55692 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
55693 DUK_TVAL_SET_OBJECT(tv_this, obj_global);
55694 DUK_HOBJECT_INCREF(thr, obj_global);
55695 } else {
55696 /* This may only happen if built-ins are being "torn down".
55697 * This behavior is out of specification scope.
55698 */
55699 DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
55700 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
55701 DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */
55702 }
55703 break;
55704 default:
55705 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
55706 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
55707 duk_to_object(ctx, idx_this); /* may have side effects */
55708 break;
55709 }
55710}
55711
55712/*
55713 * Shared helper for non-bound func lookup.
55714 *
55715 * Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
55716 */
55717
55718DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
55719 duk_idx_t idx_func,
55720 duk_idx_t *out_num_stack_args,
55721 duk_tval **out_tv_func,
55722 duk_small_uint_t call_flags) {
55723 duk_hthread *thr = (duk_hthread *) ctx;
55724 duk_tval *tv_func;
55725 duk_hobject *func;
55726
55727 for (;;) {
55728 /* Use loop to minimize code size of relookup after bound function case */
55729 tv_func = DUK_GET_TVAL_POSIDX(ctx, idx_func);
55730 DUK_ASSERT(tv_func != NULL);
55731
55732 if (DUK_TVAL_IS_OBJECT(tv_func)) {
55733 func = DUK_TVAL_GET_OBJECT(tv_func);
55734 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
55735 goto not_callable_error;
55736 }
55737 if (DUK_HOBJECT_HAS_BOUND(func)) {
55738 duk__handle_bound_chain_for_call(thr, idx_func, out_num_stack_args, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
55739
55740 /* The final object may be a normal function or a lightfunc.
55741 * We need to re-lookup tv_func because it may have changed
55742 * (also value stack may have been resized). Loop again to
55743 * do that; we're guaranteed not to come here again.
55744 */
55745 DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(ctx, idx_func)) ||
55746 DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(ctx, idx_func)));
55747 continue;
55748 }
55749 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
55750 func = NULL;
55751 } else {
55752 goto not_callable_error;
55753 }
55754 break;
55755 }
55756
55757 DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_func) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_func))) ||
55758 DUK_TVAL_IS_LIGHTFUNC(tv_func));
55759 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
55760 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
55761 DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
55762
55763 *out_tv_func = tv_func;
55764 return func;
55765
55766 not_callable_error:
55767 DUK_ASSERT(tv_func != NULL);
55768#if defined(DUK_USE_PARANOID_ERRORS)
55769 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
55770#else
55771 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func));
55772#endif
55773 DUK_UNREACHABLE();
55774 return NULL; /* never executed */
55775}
55776
55777/*
55778 * Value stack resize and stack top adjustment helper.
55779 *
55780 * XXX: This should all be merged to duk_valstack_resize_raw().
55781 */
55782
55783DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
55784 duk_idx_t num_stack_args,
55785 duk_idx_t idx_args,
55786 duk_idx_t nregs,
55787 duk_idx_t nargs,
55788 duk_hobject *func) {
55789 duk_context *ctx = (duk_context *) thr;
55790 duk_size_t vs_min_size;
55791 duk_bool_t adjusted_top = 0;
55792
55793 vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
55794 idx_args; /* bottom of new func */
55795
55796 if (nregs >= 0) {
55797 DUK_ASSERT(nargs >= 0);
55798 DUK_ASSERT(nregs >= nargs);
55799 vs_min_size += nregs;
55800 } else {
55801 /* 'func' wants stack "as is" */
55802 vs_min_size += num_stack_args; /* num entries of new func at entry */
55803 }
55804 if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
55805 vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
55806 }
55807 vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
55808
55809 /* XXX: We can't resize the value stack to a size smaller than the
55810 * current top, so the order of the resize and adjusting the stack
55811 * top depends on the current vs. final size of the value stack.
55812 * The operations could be combined to avoid this, but the proper
55813 * fix is to only grow the value stack on a function call, and only
55814 * shrink it (without throwing if the shrink fails) on function
55815 * return.
55816 */
55817
55818 if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
55819 DUK_DDD(DUK_DDDPRINT(("final size smaller, set top before resize")));
55820
55821 DUK_ASSERT(nregs >= 0); /* can't happen when keeping current stack size */
55822 duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
55823 duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
55824 adjusted_top = 1;
55825 }
55826
55827 (void) duk_valstack_resize_raw((duk_context *) thr,
55828 vs_min_size,
55829 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
55830 0 /* no compact */ |
55831 DUK_VSRESIZE_FLAG_THROW);
55832
55833 if (!adjusted_top) {
55834 if (nregs >= 0) {
55835 DUK_ASSERT(nregs >= nargs);
55836 duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
55837 duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
55838 }
55839 }
55840}
55841
55842/*
55843 * Manipulate value stack so that exactly 'num_stack_rets' return
55844 * values are at 'idx_retbase' in every case, assuming there are
55845 * 'rc' return values on top of stack.
55846 *
55847 * This is a bit tricky, because the called C function operates in
55848 * the same activation record and may have e.g. popped the stack
55849 * empty (below idx_retbase).
55850 */
55851
55852DUK_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) {
55853 duk_context *ctx = (duk_context *) thr;
55854 duk_idx_t idx_rcbase;
55855
55856 DUK_ASSERT(thr != NULL);
55857 DUK_ASSERT(idx_retbase >= 0);
55858 DUK_ASSERT(num_stack_rets >= 0);
55859 DUK_ASSERT(num_actual_rets >= 0);
55860
55861 idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
55862
55863 DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
55864 "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
55865 (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
55866 (long) idx_retbase, (long) idx_rcbase));
55867
55868 DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
55869
55870 /* Ensure space for final configuration (idx_retbase + num_stack_rets)
55871 * and intermediate configurations.
55872 */
55873 duk_require_stack_top(ctx,
55874 (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
55875 num_stack_rets);
55876
55877 /* Chop extra retvals away / extend with undefined. */
55878 duk_set_top(ctx, idx_rcbase + num_stack_rets);
55879
55880 if (idx_rcbase >= idx_retbase) {
55881 duk_idx_t count = idx_rcbase - idx_retbase;
55882 duk_idx_t i;
55883
55884 DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
55885 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
55886
55887 /* nuke values at idx_retbase to get the first retval (initially
55888 * at idx_rcbase) to idx_retbase
55889 */
55890
55891 DUK_ASSERT(count >= 0);
55892
55893 for (i = 0; i < count; i++) {
55894 /* XXX: inefficient; block remove primitive */
55895 duk_remove(ctx, idx_retbase);
55896 }
55897 } else {
55898 duk_idx_t count = idx_retbase - idx_rcbase;
55899 duk_idx_t i;
55900
55901 DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
55902 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
55903
55904 /* insert 'undefined' values at idx_rcbase to get the
55905 * return values to idx_retbase
55906 */
55907
55908 DUK_ASSERT(count > 0);
55909
55910 for (i = 0; i < count; i++) {
55911 /* XXX: inefficient; block insert primitive */
55912 duk_push_undefined(ctx);
55913 duk_insert(ctx, idx_rcbase);
55914 }
55915 }
55916}
55917
55918/*
55919 * Misc shared helpers.
55920 */
55921
55922/* Get valstack index for the func argument or throw if insane stack. */
55923DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args) {
55924 duk_size_t off_stack_top;
55925 duk_size_t off_stack_args;
55926 duk_size_t off_stack_all;
55927 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
55928
55929 /* Argument validation and func/args offset. */
55930 off_stack_top = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack_bottom);
55931 off_stack_args = (duk_size_t) ((duk_size_t) num_stack_args * sizeof(duk_tval));
55932 off_stack_all = off_stack_args + 2 * sizeof(duk_tval);
55933 if (DUK_UNLIKELY(off_stack_all > off_stack_top)) {
55934 /* Since stack indices are not reliable, we can't do anything useful
55935 * here. Invoke the existing setjmp catcher, or if it doesn't exist,
55936 * call the fatal error handler.
55937 */
55938 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
55939 return 0;
55940 }
55941 idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
55942 return idx_func;
55943}
55944
55945/*
55946 * duk_handle_call_protected() and duk_handle_call_unprotected():
55947 * call into a Duktape/C or an Ecmascript function from any state.
55948 *
55949 * Input stack (thr):
55950 *
55951 * [ func this arg1 ... argN ]
55952 *
55953 * Output stack (thr):
55954 *
55955 * [ retval ] (DUK_EXEC_SUCCESS)
55956 * [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
55957 *
55958 * Even when executing a protected call an error may be thrown in rare cases
55959 * such as an insane num_stack_args argument. If there is no catchpoint for
55960 * such errors, the fatal error handler is called.
55961 *
55962 * The error handling path should be error free, even for out-of-memory
55963 * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
55964 * yet the case, see XXX notes below.)
55965 */
55966
55967DUK_INTERNAL duk_int_t duk_handle_call_protected(duk_hthread *thr,
55968 duk_idx_t num_stack_args,
55969 duk_small_uint_t call_flags) {
55970 duk_context *ctx;
55971 duk_size_t entry_valstack_bottom_index;
55972 duk_size_t entry_valstack_end;
55973 duk_size_t entry_callstack_top;
55974 duk_size_t entry_catchstack_top;
55975 duk_int_t entry_call_recursion_depth;
55976 duk_hthread *entry_curr_thread;
55977 duk_uint_fast8_t entry_thread_state;
55978 duk_instr_t **entry_ptr_curr_pc;
55979 duk_jmpbuf *old_jmpbuf_ptr = NULL;
55980 duk_jmpbuf our_jmpbuf;
55981 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
55982
55983 /* XXX: Multiple tv_func lookups are now avoided by making a local
55984 * copy of tv_func. Another approach would be to compute an offset
55985 * for tv_func from valstack bottom and recomputing the tv_func
55986 * pointer quickly as valstack + offset instead of calling duk_get_tval().
55987 */
55988
55989 ctx = (duk_context *) thr;
55990 DUK_UNREF(ctx);
55991 DUK_ASSERT(thr != NULL);
55992 DUK_ASSERT_CTX_VALID(ctx);
55993 DUK_ASSERT(num_stack_args >= 0);
55994 /* XXX: currently NULL allocations are not supported; remove if later allowed */
55995 DUK_ASSERT(thr->valstack != NULL);
55996 DUK_ASSERT(thr->callstack != NULL);
55997 DUK_ASSERT(thr->catchstack != NULL);
55998
55999 /* Argument validation and func/args offset. */
56000 idx_func = duk__get_idx_func(thr, num_stack_args);
56001
56002 /* Preliminaries, required by setjmp() handler. Must be careful not
56003 * to throw an unintended error here.
56004 */
56005
56006 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
56007#if defined(DUK_USE_PREFER_SIZE)
56008 entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
56009#else
56010 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
56011 entry_valstack_end = thr->valstack_size;
56012#endif
56013 entry_callstack_top = thr->callstack_top;
56014 entry_catchstack_top = thr->catchstack_top;
56015 entry_call_recursion_depth = thr->heap->call_recursion_depth;
56016 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
56017 entry_thread_state = thr->state;
56018 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
56019
56020 DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
56021 "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
56022 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
56023 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
56024 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
56025 (void *) thr,
56026 (long) num_stack_args,
56027 (unsigned long) call_flags,
56028 (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
56029 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
56030 (long) duk_get_top(ctx),
56031 (long) idx_func,
56032 (long) (idx_func + 2),
56033 (long) thr->heap->call_recursion_depth,
56034 (long) thr->heap->call_recursion_limit,
56035 (long) entry_valstack_bottom_index,
56036 (long) entry_callstack_top,
56037 (long) entry_catchstack_top,
56038 (long) entry_call_recursion_depth,
56039 (void *) entry_curr_thread,
56040 (long) entry_thread_state));
56041
56042 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
56043 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
56044
56045#if defined(DUK_USE_CPP_EXCEPTIONS)
56046 try {
56047#else
56048 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
56049 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
56050#endif
56051 /* Call handling and success path. Success path exit cleans
56052 * up almost all state.
56053 */
56054 duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
56055
56056 /* Success path handles */
56057 DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
56058 DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
56059
56060 /* Longjmp state is kept clean in success path */
56061 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56062 DUK_ASSERT(thr->heap->lj.iserror == 0);
56063 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56064 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56065
56066 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
56067
56068 return DUK_EXEC_SUCCESS;
56069#if defined(DUK_USE_CPP_EXCEPTIONS)
56070 } catch (duk_internal_exception &exc) {
56071#else
56072 } else {
56073#endif
56074 /* Error; error value is in heap->lj.value1. */
56075
56076#if defined(DUK_USE_CPP_EXCEPTIONS)
56077 DUK_UNREF(exc);
56078#endif
56079
56080 duk__handle_call_error(thr,
56081 entry_valstack_bottom_index,
56082 entry_valstack_end,
56083 entry_catchstack_top,
56084 entry_callstack_top,
56085 entry_call_recursion_depth,
56086 entry_curr_thread,
56087 entry_thread_state,
56088 entry_ptr_curr_pc,
56089 idx_func,
56090 old_jmpbuf_ptr);
56091
56092 /* Longjmp state is cleaned up by error handling */
56093 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56094 DUK_ASSERT(thr->heap->lj.iserror == 0);
56095 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56096 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56097 return DUK_EXEC_ERROR;
56098 }
56099#if defined(DUK_USE_CPP_EXCEPTIONS)
56100 catch (std::exception &exc) {
56101 const char *what = exc.what();
56102 if (!what) {
56103 what = "unknown";
56104 }
56105 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
56106 try {
56107 DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
56108 } catch (duk_internal_exception exc) {
56109 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
56110 DUK_UNREF(exc);
56111 duk__handle_call_error(thr,
56112 entry_valstack_bottom_index,
56113 entry_valstack_end,
56114 entry_catchstack_top,
56115 entry_callstack_top,
56116 entry_call_recursion_depth,
56117 entry_curr_thread,
56118 entry_thread_state,
56119 entry_ptr_curr_pc,
56120 idx_func,
56121 old_jmpbuf_ptr);
56122 return DUK_EXEC_ERROR;
56123 }
56124 } catch (...) {
56125 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
56126 try {
56127 DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
56128 } catch (duk_internal_exception exc) {
56129 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
56130 DUK_UNREF(exc);
56131 duk__handle_call_error(thr,
56132 entry_valstack_bottom_index,
56133 entry_valstack_end,
56134 entry_catchstack_top,
56135 entry_callstack_top,
56136 entry_call_recursion_depth,
56137 entry_curr_thread,
56138 entry_thread_state,
56139 entry_ptr_curr_pc,
56140 idx_func,
56141 old_jmpbuf_ptr);
56142 return DUK_EXEC_ERROR;
56143 }
56144 }
56145#endif
56146}
56147
56148DUK_INTERNAL void duk_handle_call_unprotected(duk_hthread *thr,
56149 duk_idx_t num_stack_args,
56150 duk_small_uint_t call_flags) {
56151 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
56152
56153 /* Argument validation and func/args offset. */
56154 idx_func = duk__get_idx_func(thr, num_stack_args);
56155
56156 duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
56157}
56158
56159DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
56160 duk_idx_t num_stack_args,
56161 duk_small_uint_t call_flags,
56162 duk_idx_t idx_func) {
56163 duk_context *ctx;
56164 duk_size_t entry_valstack_bottom_index;
56165 duk_size_t entry_valstack_end;
56166 duk_size_t entry_callstack_top;
56167 duk_size_t entry_catchstack_top;
56168 duk_int_t entry_call_recursion_depth;
56169 duk_hthread *entry_curr_thread;
56170 duk_uint_fast8_t entry_thread_state;
56171 duk_instr_t **entry_ptr_curr_pc;
56172 duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
56173 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
56174 duk_hobject *func; /* 'func' on stack (borrowed reference) */
56175 duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
56176 duk_tval tv_func_copy; /* to avoid relookups */
56177 duk_activation *act;
56178 duk_hobject *env;
56179 duk_ret_t rc;
56180
56181 ctx = (duk_context *) thr;
56182 DUK_ASSERT(thr != NULL);
56183 DUK_ASSERT_CTX_VALID(ctx);
56184 DUK_ASSERT(ctx != NULL);
56185 DUK_ASSERT(num_stack_args >= 0);
56186 /* XXX: currently NULL allocations are not supported; remove if later allowed */
56187 DUK_ASSERT(thr->valstack != NULL);
56188 DUK_ASSERT(thr->callstack != NULL);
56189 DUK_ASSERT(thr->catchstack != NULL);
56190
56191 DUK_DD(DUK_DDPRINT("duk__handle_call_inner: num_stack_args=%ld, call_flags=0x%08lx, top=%ld",
56192 (long) num_stack_args, (long) call_flags, (long) duk_get_top(ctx)));
56193
56194 /*
56195 * Store entry state.
56196 */
56197
56198 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
56199#if defined(DUK_USE_PREFER_SIZE)
56200 entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
56201#else
56202 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
56203 entry_valstack_end = thr->valstack_size;
56204#endif
56205 entry_callstack_top = thr->callstack_top;
56206 entry_catchstack_top = thr->catchstack_top;
56207 entry_call_recursion_depth = thr->heap->call_recursion_depth;
56208 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
56209 entry_thread_state = thr->state;
56210 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
56211
56212 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
56213 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
56214 * activation when side effects occur.
56215 */
56216 duk_hthread_sync_and_null_currpc(thr);
56217
56218 DUK_DD(DUK_DDPRINT("duk__handle_call_inner: thr=%p, num_stack_args=%ld, "
56219 "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
56220 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
56221 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
56222 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
56223 (void *) thr,
56224 (long) num_stack_args,
56225 (unsigned long) call_flags,
56226 (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
56227 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
56228 (long) duk_get_top(ctx),
56229 (long) idx_func,
56230 (long) (idx_func + 2),
56231 (long) thr->heap->call_recursion_depth,
56232 (long) thr->heap->call_recursion_limit,
56233 (long) entry_valstack_bottom_index,
56234 (long) entry_callstack_top,
56235 (long) entry_catchstack_top,
56236 (long) entry_call_recursion_depth,
56237 (void *) entry_curr_thread,
56238 (long) entry_thread_state));
56239
56240
56241 /*
56242 * Thread state check and book-keeping.
56243 */
56244
56245 if (thr == thr->heap->curr_thread) {
56246 /* same thread */
56247 if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
56248 /* should actually never happen, but check anyway */
56249 goto thread_state_error;
56250 }
56251 } else {
56252 /* different thread */
56253 DUK_ASSERT(thr->heap->curr_thread == NULL ||
56254 thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
56255 if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
56256 goto thread_state_error;
56257 }
56258 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
56259 thr->state = DUK_HTHREAD_STATE_RUNNING;
56260
56261 /* Note: multiple threads may be simultaneously in the RUNNING
56262 * state, but not in the same "resume chain".
56263 */
56264 }
56265 DUK_ASSERT(thr->heap->curr_thread == thr);
56266 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
56267
56268 /*
56269 * C call recursion depth check, which provides a reasonable upper
56270 * bound on maximum C stack size (arbitrary C stack growth is only
56271 * possible by recursive handle_call / handle_safe_call calls).
56272 */
56273
56274 /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
56275 * reclimit bump?
56276 */
56277
56278 DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
56279 DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
56280 if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
56281 DUK_DD(DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)"));
56282 } else {
56283 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
56284 /* XXX: error message is a bit misleading: we reached a recursion
56285 * limit which is also essentially the same as a C callstack limit
56286 * (except perhaps with some relaxed threading assumptions).
56287 */
56288 DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
56289 }
56290 thr->heap->call_recursion_depth++;
56291 }
56292
56293 /*
56294 * Check the function type, handle bound function chains, and prepare
56295 * parameters for the rest of the call handling. Also figure out the
56296 * effective 'this' binding, which replaces the current value at
56297 * idx_func + 1.
56298 *
56299 * If the target function is a 'bound' one, follow the chain of 'bound'
56300 * functions until a non-bound function is found. During this process,
56301 * bound arguments are 'prepended' to existing ones, and the "this"
56302 * binding is overridden. See E5 Section 15.3.4.5.1.
56303 *
56304 * Lightfunc detection happens here too. Note that lightweight functions
56305 * can be wrapped by (non-lightweight) bound functions so we must resolve
56306 * the bound function chain first.
56307 */
56308
56309 func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
56310 DUK_TVAL_SET_TVAL(&tv_func_copy, tv_func);
56311 tv_func = &tv_func_copy; /* local copy to avoid relookups */
56312
56313 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
56314 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
56315 DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
56316
56317 duk__coerce_effective_this_binding(thr, func, idx_func + 1);
56318 DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
56319 (duk_tval *) duk_get_tval(ctx, idx_func + 1)));
56320
56321 /* [ ... func this arg1 ... argN ] */
56322
56323 /*
56324 * Setup a preliminary activation and figure out nargs/nregs.
56325 *
56326 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
56327 * calls work normally.
56328 */
56329
56330 duk_hthread_callstack_grow(thr);
56331
56332 if (thr->callstack_top > 0) {
56333 /*
56334 * Update idx_retval of current activation.
56335 *
56336 * Although it might seem this is not necessary (bytecode executor
56337 * does this for Ecmascript-to-Ecmascript calls; other calls are
56338 * handled here), this turns out to be necessary for handling yield
56339 * and resume. For them, an Ecmascript-to-native call happens, and
56340 * the Ecmascript call's idx_retval must be set for things to work.
56341 */
56342
56343 (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func;
56344 }
56345
56346 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
56347 act = thr->callstack + thr->callstack_top;
56348 thr->callstack_top++;
56349 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
56350 DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */
56351 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
56352
56353 act->flags = 0;
56354
56355 /* For now all calls except Ecma-to-Ecma calls prevent a yield. */
56356 act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
56357 if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
56358 act->flags |= DUK_ACT_FLAG_CONSTRUCT;
56359 }
56360 if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
56361 act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
56362 }
56363
56364 /* These base values are never used, but if the compiler doesn't know
56365 * that DUK_ERROR() won't return, these are needed to silence warnings.
56366 * On the other hand, scan-build will warn about the values not being
56367 * used, so add a DUK_UNREF.
56368 */
56369 nargs = 0; DUK_UNREF(nargs);
56370 nregs = 0; DUK_UNREF(nregs);
56371
56372 if (DUK_LIKELY(func != NULL)) {
56373 if (DUK_HOBJECT_HAS_STRICT(func)) {
56374 act->flags |= DUK_ACT_FLAG_STRICT;
56375 }
56376 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
56377 nargs = ((duk_hcompiledfunction *) func)->nargs;
56378 nregs = ((duk_hcompiledfunction *) func)->nregs;
56379 DUK_ASSERT(nregs >= nargs);
56380 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
56381 /* Note: nargs (and nregs) may be negative for a native,
56382 * function, which indicates that the function wants the
56383 * input stack "as is" (i.e. handles "vararg" arguments).
56384 */
56385 nargs = ((duk_hnativefunction *) func)->nargs;
56386 nregs = nargs;
56387 } else {
56388 /* XXX: this should be an assert */
56389 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
56390 }
56391 } else {
56392 duk_small_uint_t lf_flags;
56393
56394 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
56395 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
56396 nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
56397 if (nargs == DUK_LFUNC_NARGS_VARARGS) {
56398 nargs = -1; /* vararg */
56399 }
56400 nregs = nargs;
56401
56402 act->flags |= DUK_ACT_FLAG_STRICT;
56403 }
56404
56405 act->func = func; /* NULL for lightfunc */
56406 act->var_env = NULL;
56407 act->lex_env = NULL;
56408#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
56409 act->prev_caller = NULL;
56410#endif
56411 act->curr_pc = NULL;
56412#if defined(DUK_USE_DEBUGGER_SUPPORT)
56413 act->prev_line = 0;
56414#endif
56415 act->idx_bottom = entry_valstack_bottom_index + idx_func + 2;
56416#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
56417 act->idx_retval = 0;
56418#endif
56419 DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
56420
56421 /* XXX: remove the preventcount and make yield walk the callstack?
56422 * Or perhaps just use a single flag, not a counter, faster to just
56423 * set and restore?
56424 */
56425 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
56426 /* duk_hthread_callstack_unwind() will decrease this on unwind */
56427 thr->callstack_preventcount++;
56428 }
56429
56430 /* XXX: Is this INCREF necessary? 'func' is always a borrowed
56431 * reference reachable through the value stack? If changed, stack
56432 * unwind code also needs to be fixed to match.
56433 */
56434 DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
56435
56436#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
56437 if (func) {
56438 duk__update_func_caller_prop(thr, func);
56439 act = thr->callstack + thr->callstack_top - 1;
56440 }
56441#endif
56442
56443 /* [ ... func this arg1 ... argN ] */
56444
56445 /*
56446 * Environment record creation and 'arguments' object creation.
56447 * Named function expression name binding is handled by the
56448 * compiler; the compiled function's parent env will contain
56449 * the (immutable) binding already.
56450 *
56451 * This handling is now identical for C and Ecmascript functions.
56452 * C functions always have the 'NEWENV' flag set, so their
56453 * environment record initialization is delayed (which is good).
56454 *
56455 * Delayed creation (on demand) is handled in duk_js_var.c.
56456 */
56457
56458 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
56459
56460 if (DUK_LIKELY(func != NULL)) {
56461 if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
56462 if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
56463 /* Use a new environment but there's no 'arguments' object;
56464 * delayed environment initialization. This is the most
56465 * common case.
56466 */
56467 DUK_ASSERT(act->lex_env == NULL);
56468 DUK_ASSERT(act->var_env == NULL);
56469 } else {
56470 /* Use a new environment and there's an 'arguments' object.
56471 * We need to initialize it right now.
56472 */
56473
56474 /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
56475 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
56476 DUK_ASSERT(env != NULL);
56477
56478 /* [ ... func this arg1 ... argN envobj ] */
56479
56480 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
56481 duk__handle_createargs_for_call(thr, func, env, num_stack_args);
56482
56483 /* [ ... func this arg1 ... argN envobj ] */
56484
56485 act = thr->callstack + thr->callstack_top - 1;
56486 act->lex_env = env;
56487 act->var_env = env;
56488 DUK_HOBJECT_INCREF(thr, env);
56489 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
56490 duk_pop(ctx);
56491 }
56492 } else {
56493 /* Use existing env (e.g. for non-strict eval); cannot have
56494 * an own 'arguments' object (but can refer to an existing one).
56495 */
56496
56497 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
56498
56499 duk__handle_oldenv_for_call(thr, func, act);
56500 /* No need to re-lookup 'act' at present: no side effects. */
56501
56502 DUK_ASSERT(act->lex_env != NULL);
56503 DUK_ASSERT(act->var_env != NULL);
56504 }
56505 } else {
56506 /* Lightfuncs are always native functions and have "newenv". */
56507 DUK_ASSERT(act->lex_env == NULL);
56508 DUK_ASSERT(act->var_env == NULL);
56509 }
56510
56511 /* [ ... func this arg1 ... argN ] */
56512
56513 /*
56514 * Setup value stack: clamp to 'nargs', fill up to 'nregs'
56515 *
56516 * Value stack may either grow or shrink, depending on the
56517 * number of func registers and the number of actual arguments.
56518 * If nregs >= 0, func wants args clamped to 'nargs'; else it
56519 * wants all args (= 'num_stack_args').
56520 */
56521
56522 /* XXX: optimize value stack operation */
56523 /* XXX: don't want to shrink allocation here */
56524
56525 duk__adjust_valstack_and_top(thr,
56526 num_stack_args,
56527 idx_func + 2,
56528 nregs,
56529 nargs,
56530 func);
56531
56532 /*
56533 * Determine call type, then finalize activation, shift to
56534 * new value stack bottom, and call the target.
56535 */
56536
56537 act = thr->callstack + thr->callstack_top - 1;
56538 if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
56539 /*
56540 * Ecmascript call
56541 */
56542
56543 duk_tval *tv_ret;
56544 duk_tval *tv_funret;
56545
56546 DUK_ASSERT(func != NULL);
56547 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
56548 act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
56549
56550 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
56551 /* keep current valstack_top */
56552 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56553 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56554 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
56555
56556 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
56557
56558 /*
56559 * Bytecode executor call.
56560 *
56561 * Execute bytecode, handling any recursive function calls and
56562 * thread resumptions. Returns when execution would return from
56563 * the entry level activation. When the executor returns, a
56564 * single return value is left on the stack top.
56565 *
56566 * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
56567 * other types are handled internally by the executor.
56568 */
56569
56570 /* thr->ptr_curr_pc is set by bytecode executor early on entry */
56571 DUK_ASSERT(thr->ptr_curr_pc == NULL);
56572 DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
56573 duk_js_execute_bytecode(thr);
56574 DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
56575
56576 /* Unwind. */
56577
56578 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
56579 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
56580 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
56581 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
56582 duk_hthread_catchstack_shrink_check(thr);
56583 duk_hthread_callstack_unwind(thr, entry_callstack_top);
56584 duk_hthread_callstack_shrink_check(thr);
56585
56586 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
56587 /* keep current valstack_top */
56588 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56589 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56590 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
56591 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
56592
56593 /* Return value handling. */
56594
56595 /* [ ... func this (crud) retval ] */
56596
56597 tv_ret = thr->valstack_bottom + idx_func;
56598 tv_funret = thr->valstack_top - 1;
56599#if defined(DUK_USE_FASTINT)
56600 /* Explicit check for fastint downgrade. */
56601 DUK_TVAL_CHKFAST_INPLACE(tv_funret);
56602#endif
56603 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
56604 } else {
56605 /*
56606 * Native call.
56607 */
56608
56609 duk_tval *tv_ret;
56610 duk_tval *tv_funret;
56611
56612 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
56613 /* keep current valstack_top */
56614 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56615 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56616 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
56617 DUK_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
56618
56619 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
56620
56621 /* For native calls must be NULL so we don't sync back */
56622 DUK_ASSERT(thr->ptr_curr_pc == NULL);
56623
56624 if (func) {
56625 rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
56626 } else {
56627 duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
56628 rc = funcptr((duk_context *) thr);
56629 }
56630
56631 /* Automatic error throwing, retval check. */
56632
56633 if (rc < 0) {
56634 duk_error_throw_from_negative_rc(thr, rc);
56635 DUK_UNREACHABLE();
56636 } else if (rc > 1) {
56637 DUK_ERROR_API(thr, "c function returned invalid rc");
56638 }
56639 DUK_ASSERT(rc == 0 || rc == 1);
56640
56641 /* Unwind. */
56642
56643 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
56644 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
56645 duk_hthread_callstack_unwind(thr, entry_callstack_top);
56646 duk_hthread_callstack_shrink_check(thr);
56647
56648 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
56649 /* keep current valstack_top */
56650 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56651 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56652 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
56653 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
56654
56655 /* Return value handling. */
56656
56657 /* XXX: should this happen in the callee's activation or after unwinding? */
56658 tv_ret = thr->valstack_bottom + idx_func;
56659 if (rc == 0) {
56660 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv_ret); /* side effects */
56661 } else {
56662 /* [ ... func this (crud) retval ] */
56663 tv_funret = thr->valstack_top - 1;
56664#if defined(DUK_USE_FASTINT)
56665 /* Explicit check for fastint downgrade. */
56666 DUK_TVAL_CHKFAST_INPLACE(tv_funret);
56667#endif
56668 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
56669 }
56670 }
56671
56672 duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
56673
56674 /* [ ... retval ] */
56675
56676 /* Ensure there is internal valstack spare before we exit; this may
56677 * throw an alloc error. The same guaranteed size must be available
56678 * as before the call. This is not optimal now: we store the valstack
56679 * allocated size during entry; this value may be higher than the
56680 * minimal guarantee for an application.
56681 */
56682
56683 /* XXX: we should never shrink here; when we error out later, we'd
56684 * need to potentially grow the value stack in error unwind which could
56685 * cause another error.
56686 */
56687
56688 (void) duk_valstack_resize_raw((duk_context *) thr,
56689 entry_valstack_end, /* same as during entry */
56690 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
56691 DUK_VSRESIZE_FLAG_COMPACT |
56692 DUK_VSRESIZE_FLAG_THROW);
56693
56694 /* Restore entry thread executor curr_pc stack frame pointer. */
56695 thr->ptr_curr_pc = entry_ptr_curr_pc;
56696
56697 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
56698 thr->state = (duk_uint8_t) entry_thread_state;
56699
56700 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
56701 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
56702 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
56703
56704 thr->heap->call_recursion_depth = entry_call_recursion_depth;
56705
56706 /* If the debugger is active we need to force an interrupt so that
56707 * debugger breakpoints are rechecked. This is important for function
56708 * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
56709 * GH-303. Only needed for success path, error path always causes a
56710 * breakpoint recheck in the executor. It would be enough to set this
56711 * only when returning to an Ecmascript activation, but setting the flag
56712 * on every return should have no ill effect.
56713 */
56714#if defined(DUK_USE_DEBUGGER_SUPPORT)
56715 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
56716 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
56717 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
56718 thr->interrupt_init -= thr->interrupt_counter;
56719 thr->interrupt_counter = 0;
56720 thr->heap->dbg_force_restart = 1;
56721 }
56722#endif
56723
56724#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
56725 duk__interrupt_fixup(thr, entry_curr_thread);
56726#endif
56727
56728 return;
56729
56730 thread_state_error:
56731 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
56732 DUK_UNREACHABLE();
56733 return; /* never executed */
56734}
56735
56736DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
56737 duk_size_t entry_valstack_bottom_index,
56738 duk_size_t entry_valstack_end,
56739 duk_size_t entry_catchstack_top,
56740 duk_size_t entry_callstack_top,
56741 duk_int_t entry_call_recursion_depth,
56742 duk_hthread *entry_curr_thread,
56743 duk_uint_fast8_t entry_thread_state,
56744 duk_instr_t **entry_ptr_curr_pc,
56745 duk_idx_t idx_func,
56746 duk_jmpbuf *old_jmpbuf_ptr) {
56747 duk_context *ctx;
56748 duk_tval *tv_ret;
56749
56750 ctx = (duk_context *) thr;
56751
56752 DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
56753 (duk_tval *) &thr->heap->lj.value1));
56754
56755 /* Other longjmp types are handled by executor before propagating
56756 * the error here.
56757 */
56758 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
56759 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
56760 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
56761
56762 /* We don't need to sync back thr->ptr_curr_pc here because
56763 * the bytecode executor always has a setjmp catchpoint which
56764 * does that before errors propagate to here.
56765 */
56766 DUK_ASSERT(thr->ptr_curr_pc == NULL);
56767
56768 /* Restore the previous setjmp catcher so that any error in
56769 * error handling will propagate outwards rather than re-enter
56770 * the same handler. However, the error handling path must be
56771 * designed to be error free so that sandboxing guarantees are
56772 * reliable, see e.g. https://github.com/svaarala/duktape/issues/476.
56773 */
56774 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
56775
56776 /* XXX: callstack unwind may now throw an error when closing
56777 * scopes; this is a sandboxing issue, described in:
56778 * https://github.com/svaarala/duktape/issues/476
56779 */
56780 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
56781 duk_hthread_catchstack_shrink_check(thr);
56782 duk_hthread_callstack_unwind(thr, entry_callstack_top);
56783 duk_hthread_callstack_shrink_check(thr);
56784
56785 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
56786 tv_ret = thr->valstack_bottom + idx_func; /* XXX: byte offset? */
56787 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */
56788#if defined(DUK_USE_FASTINT)
56789 /* Explicit check for fastint downgrade. */
56790 DUK_TVAL_CHKFAST_INPLACE(tv_ret);
56791#endif
56792 duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
56793
56794 /* [ ... errobj ] */
56795
56796 /* Ensure there is internal valstack spare before we exit; this may
56797 * throw an alloc error. The same guaranteed size must be available
56798 * as before the call. This is not optimal now: we store the valstack
56799 * allocated size during entry; this value may be higher than the
56800 * minimal guarantee for an application.
56801 */
56802
56803 /* XXX: this needs to be reworked so that we never shrink the value
56804 * stack on function entry so that we never need to grow it here.
56805 * Needing to grow here is a sandboxing issue because we need to
56806 * allocate which may cause an error in the error handling path
56807 * and thus propagate an error out of a protected call.
56808 */
56809
56810 (void) duk_valstack_resize_raw((duk_context *) thr,
56811 entry_valstack_end, /* same as during entry */
56812 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
56813 DUK_VSRESIZE_FLAG_COMPACT |
56814 DUK_VSRESIZE_FLAG_THROW);
56815
56816
56817 /* These are just convenience "wiping" of state. Side effects should
56818 * not be an issue here: thr->heap and thr->heap->lj have a stable
56819 * pointer. Finalizer runs etc capture even out-of-memory errors so
56820 * nothing should throw here.
56821 */
56822 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
56823 thr->heap->lj.iserror = 0;
56824 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
56825 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
56826
56827 /* Restore entry thread executor curr_pc stack frame pointer. */
56828 thr->ptr_curr_pc = entry_ptr_curr_pc;
56829
56830 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
56831 thr->state = (duk_uint8_t) entry_thread_state;
56832
56833 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
56834 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
56835 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
56836
56837 thr->heap->call_recursion_depth = entry_call_recursion_depth;
56838
56839 /* If the debugger is active we need to force an interrupt so that
56840 * debugger breakpoints are rechecked. This is important for function
56841 * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
56842 * GH-303. Only needed for success path, error path always causes a
56843 * breakpoint recheck in the executor. It would be enough to set this
56844 * only when returning to an Ecmascript activation, but setting the flag
56845 * on every return should have no ill effect.
56846 */
56847#if defined(DUK_USE_DEBUGGER_SUPPORT)
56848 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
56849 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
56850 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
56851 thr->interrupt_init -= thr->interrupt_counter;
56852 thr->interrupt_counter = 0;
56853 thr->heap->dbg_force_restart = 1;
56854 }
56855#endif
56856
56857#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
56858 duk__interrupt_fixup(thr, entry_curr_thread);
56859#endif
56860}
56861
56862/*
56863 * duk_handle_safe_call(): make a "C protected call" within the
56864 * current activation.
56865 *
56866 * The allowed thread states for making a call are the same as for
56867 * duk_handle_call_xxx().
56868 *
56869 * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
56870 * (and result in a fatal error) for insane arguments.
56871 */
56872
56873/* XXX: bump preventcount by one for the duration of this call? */
56874
56875DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
56876 duk_safe_call_function func,
56877 duk_idx_t num_stack_args,
56878 duk_idx_t num_stack_rets) {
56879 duk_context *ctx = (duk_context *) thr;
56880 duk_size_t entry_valstack_bottom_index;
56881 duk_size_t entry_callstack_top;
56882 duk_size_t entry_catchstack_top;
56883 duk_int_t entry_call_recursion_depth;
56884 duk_hthread *entry_curr_thread;
56885 duk_uint_fast8_t entry_thread_state;
56886 duk_instr_t **entry_ptr_curr_pc;
56887 duk_jmpbuf *old_jmpbuf_ptr = NULL;
56888 duk_jmpbuf our_jmpbuf;
56889 duk_idx_t idx_retbase;
56890 duk_int_t retval;
56891
56892 DUK_ASSERT(thr != NULL);
56893 DUK_ASSERT(ctx != NULL);
56894
56895 /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
56896 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
56897 entry_callstack_top = thr->callstack_top;
56898 entry_catchstack_top = thr->catchstack_top;
56899 entry_call_recursion_depth = thr->heap->call_recursion_depth;
56900 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
56901 entry_thread_state = thr->state;
56902 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
56903 idx_retbase = duk_get_top(ctx) - num_stack_args; /* Note: not a valid stack index if num_stack_args == 0 */
56904
56905 /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
56906 DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
56907 "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
56908 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
56909 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
56910 (void *) thr,
56911 (long) num_stack_args,
56912 (long) num_stack_rets,
56913 (long) duk_get_top(ctx),
56914 (long) idx_retbase,
56915 (long) thr->heap->call_recursion_depth,
56916 (long) thr->heap->call_recursion_limit,
56917 (long) entry_valstack_bottom_index,
56918 (long) entry_callstack_top,
56919 (long) entry_catchstack_top,
56920 (long) entry_call_recursion_depth,
56921 (void *) entry_curr_thread,
56922 (long) entry_thread_state));
56923
56924 if (idx_retbase < 0) {
56925 /* Since stack indices are not reliable, we can't do anything useful
56926 * here. Invoke the existing setjmp catcher, or if it doesn't exist,
56927 * call the fatal error handler.
56928 */
56929
56930 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
56931 }
56932
56933 /* setjmp catchpoint setup */
56934
56935 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
56936 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
56937
56938#if defined(DUK_USE_CPP_EXCEPTIONS)
56939 try {
56940#else
56941 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
56942 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
56943 /* Success path. */
56944#endif
56945 DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
56946
56947 duk__handle_safe_call_inner(thr,
56948 func,
56949 idx_retbase,
56950 num_stack_rets,
56951 entry_valstack_bottom_index,
56952 entry_callstack_top,
56953 entry_catchstack_top);
56954
56955 /* Longjmp state is kept clean in success path */
56956 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56957 DUK_ASSERT(thr->heap->lj.iserror == 0);
56958 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56959 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56960
56961 /* Note: either pointer may be NULL (at entry), so don't assert */
56962 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
56963
56964 retval = DUK_EXEC_SUCCESS;
56965#if defined(DUK_USE_CPP_EXCEPTIONS)
56966 } catch (duk_internal_exception &exc) {
56967 DUK_UNREF(exc);
56968#else
56969 } else {
56970 /* Error path. */
56971#endif
56972 duk__handle_safe_call_error(thr,
56973 idx_retbase,
56974 num_stack_rets,
56975 entry_valstack_bottom_index,
56976 entry_callstack_top,
56977 entry_catchstack_top,
56978 old_jmpbuf_ptr);
56979
56980 /* Longjmp state is cleaned up by error handling */
56981 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56982 DUK_ASSERT(thr->heap->lj.iserror == 0);
56983 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56984 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56985
56986 retval = DUK_EXEC_ERROR;
56987 }
56988#if defined(DUK_USE_CPP_EXCEPTIONS)
56989 catch (std::exception &exc) {
56990 const char *what = exc.what();
56991 if (!what) {
56992 what = "unknown";
56993 }
56994 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
56995 try {
56996 DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
56997 } catch (duk_internal_exception exc) {
56998 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
56999 DUK_UNREF(exc);
57000 duk__handle_safe_call_error(thr,
57001 idx_retbase,
57002 num_stack_rets,
57003 entry_valstack_bottom_index,
57004 entry_callstack_top,
57005 entry_catchstack_top,
57006 old_jmpbuf_ptr);
57007 retval = DUK_EXEC_ERROR;
57008 }
57009 } catch (...) {
57010 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
57011 try {
57012 DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
57013 } catch (duk_internal_exception exc) {
57014 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
57015 DUK_UNREF(exc);
57016 duk__handle_safe_call_error(thr,
57017 idx_retbase,
57018 num_stack_rets,
57019 entry_valstack_bottom_index,
57020 entry_callstack_top,
57021 entry_catchstack_top,
57022 old_jmpbuf_ptr);
57023 retval = DUK_EXEC_ERROR;
57024 }
57025 }
57026#endif
57027
57028 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
57029
57030 duk__handle_safe_call_shared(thr,
57031 idx_retbase,
57032 num_stack_rets,
57033 entry_call_recursion_depth,
57034 entry_curr_thread,
57035 entry_thread_state,
57036 entry_ptr_curr_pc);
57037
57038 return retval;
57039}
57040
57041DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
57042 duk_safe_call_function func,
57043 duk_idx_t idx_retbase,
57044 duk_idx_t num_stack_rets,
57045 duk_size_t entry_valstack_bottom_index,
57046 duk_size_t entry_callstack_top,
57047 duk_size_t entry_catchstack_top) {
57048 duk_context *ctx;
57049 duk_ret_t rc;
57050
57051 DUK_ASSERT(thr != NULL);
57052 ctx = (duk_context *) thr;
57053 DUK_ASSERT_CTX_VALID(ctx);
57054 DUK_UNREF(entry_valstack_bottom_index);
57055 DUK_UNREF(entry_callstack_top);
57056 DUK_UNREF(entry_catchstack_top);
57057
57058 /*
57059 * Thread state check and book-keeping.
57060 */
57061
57062 if (thr == thr->heap->curr_thread) {
57063 /* same thread */
57064 if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
57065 /* should actually never happen, but check anyway */
57066 goto thread_state_error;
57067 }
57068 } else {
57069 /* different thread */
57070 DUK_ASSERT(thr->heap->curr_thread == NULL ||
57071 thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
57072 if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
57073 goto thread_state_error;
57074 }
57075 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
57076 thr->state = DUK_HTHREAD_STATE_RUNNING;
57077
57078 /* Note: multiple threads may be simultaneously in the RUNNING
57079 * state, but not in the same "resume chain".
57080 */
57081 }
57082
57083 DUK_ASSERT(thr->heap->curr_thread == thr);
57084 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
57085
57086 /*
57087 * Recursion limit check.
57088 *
57089 * Note: there is no need for an "ignore recursion limit" flag
57090 * for duk_handle_safe_call now.
57091 */
57092
57093 DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
57094 DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
57095 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
57096 /* XXX: error message is a bit misleading: we reached a recursion
57097 * limit which is also essentially the same as a C callstack limit
57098 * (except perhaps with some relaxed threading assumptions).
57099 */
57100 DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
57101 }
57102 thr->heap->call_recursion_depth++;
57103
57104 /*
57105 * Valstack spare check
57106 */
57107
57108 duk_require_stack(ctx, 0); /* internal spare */
57109
57110 /*
57111 * Make the C call
57112 */
57113
57114 rc = func(ctx);
57115
57116 DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
57117
57118 /*
57119 * Valstack manipulation for results.
57120 */
57121
57122 /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
57123 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
57124 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
57125 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
57126 DUK_ASSERT((duk_size_t) (thr->valstack_bottom - thr->valstack) == entry_valstack_bottom_index);
57127 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
57128 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
57129
57130 if (rc < 0) {
57131 duk_error_throw_from_negative_rc(thr, rc);
57132 }
57133 DUK_ASSERT(rc >= 0);
57134
57135 if (duk_get_top(ctx) < rc) {
57136 DUK_ERROR_API(thr, "not enough stack values for safe_call rc");
57137 }
57138
57139 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
57140 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
57141
57142 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
57143 return;
57144
57145 thread_state_error:
57146 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
57147 DUK_UNREACHABLE();
57148}
57149
57150DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
57151 duk_idx_t idx_retbase,
57152 duk_idx_t num_stack_rets,
57153 duk_size_t entry_valstack_bottom_index,
57154 duk_size_t entry_callstack_top,
57155 duk_size_t entry_catchstack_top,
57156 duk_jmpbuf *old_jmpbuf_ptr) {
57157 duk_context *ctx;
57158
57159 DUK_ASSERT(thr != NULL);
57160 ctx = (duk_context *) thr;
57161 DUK_ASSERT_CTX_VALID(ctx);
57162
57163 /*
57164 * Error during call. The error value is at heap->lj.value1.
57165 *
57166 * The very first thing we do is restore the previous setjmp catcher.
57167 * This means that any error in error handling will propagate outwards
57168 * instead of causing a setjmp() re-entry above.
57169 */
57170
57171 DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
57172
57173 /* Other longjmp types are handled by executor before propagating
57174 * the error here.
57175 */
57176 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
57177 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
57178 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
57179
57180 /* Note: either pointer may be NULL (at entry), so don't assert. */
57181 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
57182
57183 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
57184 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
57185 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
57186 duk_hthread_catchstack_shrink_check(thr);
57187 duk_hthread_callstack_unwind(thr, entry_callstack_top);
57188 duk_hthread_callstack_shrink_check(thr);
57189 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
57190
57191 /* [ ... | (crud) ] */
57192
57193 /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
57194 duk_push_tval(ctx, &thr->heap->lj.value1);
57195
57196 /* [ ... | (crud) errobj ] */
57197
57198 DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
57199
57200 /* check that the valstack has space for the final amount and any
57201 * intermediate space needed; this is unoptimal but should be safe
57202 */
57203 duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
57204 duk_require_stack(ctx, num_stack_rets);
57205
57206 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
57207
57208 /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
57209
57210 /* These are just convenience "wiping" of state. Side effects should
57211 * not be an issue here: thr->heap and thr->heap->lj have a stable
57212 * pointer. Finalizer runs etc capture even out-of-memory errors so
57213 * nothing should throw here.
57214 */
57215 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
57216 thr->heap->lj.iserror = 0;
57217 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
57218 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
57219}
57220
57221DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
57222 duk_idx_t idx_retbase,
57223 duk_idx_t num_stack_rets,
57224 duk_int_t entry_call_recursion_depth,
57225 duk_hthread *entry_curr_thread,
57226 duk_uint_fast8_t entry_thread_state,
57227 duk_instr_t **entry_ptr_curr_pc) {
57228 duk_context *ctx;
57229
57230 DUK_ASSERT(thr != NULL);
57231 ctx = (duk_context *) thr;
57232 DUK_ASSERT_CTX_VALID(ctx);
57233 DUK_UNREF(ctx);
57234 DUK_UNREF(idx_retbase);
57235 DUK_UNREF(num_stack_rets);
57236
57237 /* Restore entry thread executor curr_pc stack frame pointer. */
57238 thr->ptr_curr_pc = entry_ptr_curr_pc;
57239
57240 /* XXX: because we unwind stacks above, thr->heap->curr_thread is at
57241 * risk of pointing to an already freed thread. This was indeed the
57242 * case in test-bug-multithread-valgrind.c, until duk_handle_call()
57243 * was fixed to restore thr->heap->curr_thread before rethrowing an
57244 * uncaught error.
57245 */
57246 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
57247 thr->state = (duk_uint8_t) entry_thread_state;
57248
57249 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
57250 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
57251 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
57252
57253 thr->heap->call_recursion_depth = entry_call_recursion_depth;
57254
57255 /* stack discipline consistency check */
57256 DUK_ASSERT(duk_get_top(ctx) == idx_retbase + num_stack_rets);
57257
57258 /* A debugger forced interrupt check is not needed here, as
57259 * problematic safe calls are not caused by side effects.
57260 */
57261
57262#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
57263 duk__interrupt_fixup(thr, entry_curr_thread);
57264#endif
57265}
57266
57267/*
57268 * Helper for handling an Ecmascript-to-Ecmascript call or an Ecmascript
57269 * function (initial) Duktape.Thread.resume().
57270 *
57271 * Compared to normal calls handled by duk_handle_call(), there are a
57272 * bunch of differences:
57273 *
57274 * - the call is never protected
57275 * - there is no C recursion depth increase (hence an "ignore recursion
57276 * limit" flag is not applicable)
57277 * - instead of making the call, this helper just performs the thread
57278 * setup and returns; the bytecode executor then restarts execution
57279 * internally
57280 * - ecmascript functions are never 'vararg' functions (they access
57281 * varargs through the 'arguments' object)
57282 *
57283 * The callstack of the target contains an earlier Ecmascript call in case
57284 * of an Ecmascript-to-Ecmascript call (whose idx_retval is updated), or
57285 * is empty in case of an initial Duktape.Thread.resume().
57286 *
57287 * The first thing to do here is to figure out whether an ecma-to-ecma
57288 * call is actually possible. It's not always the case if the target is
57289 * a bound function; the final function may be native. In that case,
57290 * return an error so caller can fall back to a normal call path.
57291 */
57292
57293DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
57294 duk_idx_t num_stack_args,
57295 duk_small_uint_t call_flags) {
57296 duk_context *ctx = (duk_context *) thr;
57297 duk_size_t entry_valstack_bottom_index;
57298 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
57299 duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
57300 duk_idx_t nargs; /* # argument registers target function wants (< 0 => never for ecma calls) */
57301 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => never for ecma calls) */
57302 duk_hobject *func; /* 'func' on stack (borrowed reference) */
57303 duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) */
57304 duk_activation *act;
57305 duk_hobject *env;
57306 duk_bool_t use_tailcall;
57307 duk_instr_t **entry_ptr_curr_pc;
57308
57309 DUK_ASSERT(thr != NULL);
57310 DUK_ASSERT(ctx != NULL);
57311 DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
57312
57313 /* XXX: assume these? */
57314 DUK_ASSERT(thr->valstack != NULL);
57315 DUK_ASSERT(thr->callstack != NULL);
57316 DUK_ASSERT(thr->catchstack != NULL);
57317
57318 /* no need to handle thread state book-keeping here */
57319 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
57320 (thr->state == DUK_HTHREAD_STATE_RUNNING &&
57321 thr->heap->curr_thread == thr));
57322
57323 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
57324 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
57325 * activation when side effects occur. If we end up not making the
57326 * call we must restore the value.
57327 */
57328 entry_ptr_curr_pc = thr->ptr_curr_pc;
57329 duk_hthread_sync_and_null_currpc(thr);
57330
57331 /* if a tail call:
57332 * - an Ecmascript activation must be on top of the callstack
57333 * - there cannot be any active catchstack entries
57334 */
57335#if defined(DUK_USE_ASSERTIONS)
57336 if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
57337 duk_size_t our_callstack_index;
57338 duk_size_t i;
57339
57340 DUK_ASSERT(thr->callstack_top >= 1);
57341 our_callstack_index = thr->callstack_top - 1;
57342 DUK_ASSERT_DISABLE(our_callstack_index >= 0);
57343 DUK_ASSERT(our_callstack_index < thr->callstack_size);
57344 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index) != NULL);
57345 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index)));
57346
57347 /* No entry in the catchstack which would actually catch a
57348 * throw can refer to the callstack entry being reused.
57349 * There *can* be catchstack entries referring to the current
57350 * callstack entry as long as they don't catch (e.g. label sites).
57351 */
57352
57353 for (i = 0; i < thr->catchstack_top; i++) {
57354 DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index || /* refer to callstack entries below current */
57355 DUK_CAT_GET_TYPE(thr->catchstack + i) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
57356 }
57357 }
57358#endif /* DUK_USE_ASSERTIONS */
57359
57360 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
57361 /* XXX: rework */
57362 idx_func = duk_normalize_index(thr, -num_stack_args - 2);
57363 idx_args = idx_func + 2;
57364
57365 DUK_DD(DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
57366 "num_stack_args=%ld, call_flags=0x%08lx (resume=%ld, tailcall=%ld), "
57367 "idx_func=%ld, idx_args=%ld, entry_valstack_bottom_index=%ld",
57368 (void *) thr,
57369 (long) num_stack_args,
57370 (unsigned long) call_flags,
57371 (long) ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
57372 (long) ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
57373 (long) idx_func,
57374 (long) idx_args,
57375 (long) entry_valstack_bottom_index));
57376
57377 if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
57378 /* XXX: assert? compiler is responsible for this never happening */
57379 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
57380 }
57381
57382 /*
57383 * Check the function type, handle bound function chains, and prepare
57384 * parameters for the rest of the call handling. Also figure out the
57385 * effective 'this' binding, which replaces the current value at
57386 * idx_func + 1.
57387 *
57388 * If the target function is a 'bound' one, follow the chain of 'bound'
57389 * functions until a non-bound function is found. During this process,
57390 * bound arguments are 'prepended' to existing ones, and the "this"
57391 * binding is overridden. See E5 Section 15.3.4.5.1.
57392 *
57393 * If the final target function cannot be handled by an ecma-to-ecma
57394 * call, return to the caller with a return value indicating this case.
57395 * The bound chain is resolved and the caller can resume with a plain
57396 * function call.
57397 */
57398
57399 func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
57400 if (func == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
57401 DUK_DDD(DUK_DDDPRINT("final target is a lightfunc/nativefunc, cannot do ecma-to-ecma call"));
57402 thr->ptr_curr_pc = entry_ptr_curr_pc;
57403 return 0;
57404 }
57405 /* XXX: tv_func is not actually needed */
57406
57407 DUK_ASSERT(func != NULL);
57408 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
57409 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(func));
57410
57411 duk__coerce_effective_this_binding(thr, func, idx_func + 1);
57412 DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
57413 duk_get_tval(ctx, idx_func + 1)));
57414
57415 nargs = ((duk_hcompiledfunction *) func)->nargs;
57416 nregs = ((duk_hcompiledfunction *) func)->nregs;
57417 DUK_ASSERT(nregs >= nargs);
57418
57419 /* [ ... func this arg1 ... argN ] */
57420
57421 /*
57422 * Preliminary activation record and valstack manipulation.
57423 * The concrete actions depend on whether the we're dealing
57424 * with a tail call (reuse an existing activation), a resume,
57425 * or a normal call.
57426 *
57427 * The basic actions, in varying order, are:
57428 *
57429 * - Check stack size for call handling
57430 * - Grow call stack if necessary (non-tail-calls)
57431 * - Update current activation (idx_retval) if necessary
57432 * (non-tail, non-resume calls)
57433 * - Move start of args (idx_args) to valstack bottom
57434 * (tail calls)
57435 *
57436 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
57437 * calls work normally.
57438 */
57439
57440 /* XXX: some overlapping code; cleanup */
57441 use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
57442#if !defined(DUK_USE_TAILCALL)
57443 DUK_ASSERT(use_tailcall == 0); /* compiler ensures this */
57444#endif
57445 if (use_tailcall) {
57446 /* tailcall cannot be flagged to resume calls, and a
57447 * previous frame must exist
57448 */
57449 DUK_ASSERT(thr->callstack_top >= 1);
57450 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0);
57451
57452 act = thr->callstack + thr->callstack_top - 1;
57453 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
57454 /* See: test-bug-tailcall-preventyield-assert.c. */
57455 DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
57456 use_tailcall = 0;
57457 } else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
57458 DUK_D(DUK_DPRINT("tail call prevented by function having a notail flag"));
57459 use_tailcall = 0;
57460 }
57461 }
57462
57463 if (use_tailcall) {
57464 duk_tval *tv1, *tv2;
57465 duk_size_t cs_index;
57466 duk_int_t i_stk; /* must be signed for loop structure */
57467 duk_idx_t i_arg;
57468
57469 /*
57470 * Tailcall handling
57471 *
57472 * Although the callstack entry is reused, we need to explicitly unwind
57473 * the current activation (or simulate an unwind). In particular, the
57474 * current activation must be closed, otherwise something like
57475 * test-bug-reduce-judofyr.js results. Also catchstack needs be unwound
57476 * because there may be non-error-catching label entries in valid tail calls.
57477 */
57478
57479 DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
57480 (long) (thr->callstack_top - 1)));
57481
57482 /* 'act' already set above */
57483
57484 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
57485 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
57486 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57487 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
57488
57489 /* Unwind catchstack entries referring to the callstack entry we're reusing */
57490 cs_index = thr->callstack_top - 1;
57491 DUK_ASSERT(thr->catchstack_top <= DUK_INT_MAX); /* catchstack limits */
57492 for (i_stk = (duk_int_t) (thr->catchstack_top - 1); i_stk >= 0; i_stk--) {
57493 duk_catcher *cat = thr->catchstack + i_stk;
57494 if (cat->callstack_index != cs_index) {
57495 /* 'i' is the first entry we'll keep */
57496 break;
57497 }
57498 }
57499 duk_hthread_catchstack_unwind(thr, i_stk + 1);
57500
57501 /* Unwind the topmost callstack entry before reusing it */
57502 DUK_ASSERT(thr->callstack_top > 0);
57503 duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
57504
57505 /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
57506 thr->callstack_top++;
57507 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
57508 act = thr->callstack + thr->callstack_top - 1;
57509
57510 /* Start filling in the activation */
57511 act->func = func; /* don't want an intermediate exposed state with func == NULL */
57512#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57513 act->prev_caller = NULL;
57514#endif
57515 DUK_ASSERT(func != NULL);
57516 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57517 /* don't want an intermediate exposed state with invalid pc */
57518 act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
57519#if defined(DUK_USE_DEBUGGER_SUPPORT)
57520 act->prev_line = 0;
57521#endif
57522 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
57523#if defined(DUK_USE_REFERENCE_COUNTING)
57524 DUK_HOBJECT_INCREF(thr, func);
57525 act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
57526#endif
57527
57528#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57529#if defined(DUK_USE_TAILCALL)
57530#error incorrect options: tail calls enabled with function caller property
57531#endif
57532 /* XXX: this doesn't actually work properly for tail calls, so
57533 * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
57534 * is in use.
57535 */
57536 duk__update_func_caller_prop(thr, func);
57537 act = thr->callstack + thr->callstack_top - 1;
57538#endif
57539
57540 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
57541 DUK_ACT_FLAG_STRICT | DUK_ACT_FLAG_TAILCALLED :
57542 DUK_ACT_FLAG_TAILCALLED);
57543
57544 DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
57545 DUK_ASSERT(act->var_env == NULL); /* already NULLed (by unwind) */
57546 DUK_ASSERT(act->lex_env == NULL); /* already NULLed (by unwind) */
57547 act->idx_bottom = entry_valstack_bottom_index; /* tail call -> reuse current "frame" */
57548 DUK_ASSERT(nregs >= 0);
57549#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
57550 act->idx_retval = 0;
57551#endif
57552
57553 /*
57554 * Manipulate valstack so that args are on the current bottom and the
57555 * previous caller's 'this' binding (which is the value preceding the
57556 * current bottom) is replaced with the new 'this' binding:
57557 *
57558 * [ ... this_old | (crud) func this_new arg1 ... argN ]
57559 * --> [ ... this_new | arg1 ... argN ]
57560 *
57561 * For tail calling to work properly, the valstack bottom must not grow
57562 * here; otherwise crud would accumulate on the valstack.
57563 */
57564
57565 tv1 = thr->valstack_bottom - 1;
57566 tv2 = thr->valstack_bottom + idx_func + 1;
57567 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
57568 DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
57569 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
57570
57571 for (i_arg = 0; i_arg < idx_args; i_arg++) {
57572 /* XXX: block removal API primitive */
57573 /* Note: 'func' is popped from valstack here, but it is
57574 * already reachable from the activation.
57575 */
57576 duk_remove(ctx, 0);
57577 }
57578 idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
57579 idx_args = 0;
57580
57581 /* [ ... this_new | arg1 ... argN ] */
57582 } else {
57583 DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
57584 (long) (thr->callstack_top)));
57585
57586 duk_hthread_callstack_grow(thr);
57587
57588 if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
57589 DUK_DDD(DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)"));
57590 } else {
57591 DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval"));
57592 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
57593 DUK_ASSERT(thr->callstack_top >= 1);
57594 act = thr->callstack + thr->callstack_top - 1;
57595 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
57596 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
57597 act->idx_retval = entry_valstack_bottom_index + idx_func;
57598 }
57599
57600 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
57601 act = thr->callstack + thr->callstack_top;
57602 thr->callstack_top++;
57603 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
57604
57605 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
57606 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
57607 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57608
57609 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
57610 DUK_ACT_FLAG_STRICT :
57611 0);
57612 act->func = func;
57613 act->var_env = NULL;
57614 act->lex_env = NULL;
57615#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57616 act->prev_caller = NULL;
57617#endif
57618 DUK_ASSERT(func != NULL);
57619 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57620 act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
57621#if defined(DUK_USE_DEBUGGER_SUPPORT)
57622 act->prev_line = 0;
57623#endif
57624 act->idx_bottom = entry_valstack_bottom_index + idx_args;
57625 DUK_ASSERT(nregs >= 0);
57626#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
57627 act->idx_retval = 0;
57628#endif
57629 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
57630
57631 DUK_HOBJECT_INCREF(thr, func); /* act->func */
57632
57633#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57634 duk__update_func_caller_prop(thr, func);
57635 act = thr->callstack + thr->callstack_top - 1;
57636#endif
57637 }
57638
57639 /* [ ... func this arg1 ... argN ] (not tail call)
57640 * [ this | arg1 ... argN ] (tail call)
57641 *
57642 * idx_args updated to match
57643 */
57644
57645 /*
57646 * Environment record creation and 'arguments' object creation.
57647 * Named function expression name binding is handled by the
57648 * compiler; the compiled function's parent env will contain
57649 * the (immutable) binding already.
57650 *
57651 * Delayed creation (on demand) is handled in duk_js_var.c.
57652 */
57653
57654 /* XXX: unify handling with native call. */
57655
57656 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
57657
57658 if (!DUK_HOBJECT_HAS_NEWENV(func)) {
57659 /* use existing env (e.g. for non-strict eval); cannot have
57660 * an own 'arguments' object (but can refer to the existing one)
57661 */
57662
57663 duk__handle_oldenv_for_call(thr, func, act);
57664 /* No need to re-lookup 'act' at present: no side effects. */
57665
57666 DUK_ASSERT(act->lex_env != NULL);
57667 DUK_ASSERT(act->var_env != NULL);
57668 goto env_done;
57669 }
57670
57671 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
57672
57673 if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
57674 /* no need to create environment record now; leave as NULL */
57675 DUK_ASSERT(act->lex_env == NULL);
57676 DUK_ASSERT(act->var_env == NULL);
57677 goto env_done;
57678 }
57679
57680 /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
57681 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
57682 DUK_ASSERT(env != NULL);
57683
57684 /* [ ... arg1 ... argN envobj ] */
57685
57686 /* original input stack before nargs/nregs handling must be
57687 * intact for 'arguments' object
57688 */
57689 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
57690 duk__handle_createargs_for_call(thr, func, env, num_stack_args);
57691
57692 /* [ ... arg1 ... argN envobj ] */
57693
57694 act = thr->callstack + thr->callstack_top - 1;
57695 act->lex_env = env;
57696 act->var_env = env;
57697 DUK_HOBJECT_INCREF(thr, act->lex_env);
57698 DUK_HOBJECT_INCREF(thr, act->var_env);
57699 duk_pop(ctx);
57700
57701 env_done:
57702 /* [ ... arg1 ... argN ] */
57703
57704 /*
57705 * Setup value stack: clamp to 'nargs', fill up to 'nregs'
57706 */
57707
57708 duk__adjust_valstack_and_top(thr,
57709 num_stack_args,
57710 idx_args,
57711 nregs,
57712 nargs,
57713 func);
57714
57715 /*
57716 * Shift to new valstack_bottom.
57717 */
57718
57719 thr->valstack_bottom = thr->valstack_bottom + idx_args;
57720 /* keep current valstack_top */
57721 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
57722 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
57723 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
57724
57725 /*
57726 * Return to bytecode executor, which will resume execution from
57727 * the topmost activation.
57728 */
57729
57730 return 1;
57731}
57732#line 1 "duk_js_compiler.c"
57733/*
57734 * Ecmascript compiler.
57735 *
57736 * Parses an input string and generates a function template result.
57737 * Compilation may happen in multiple contexts (global code, eval
57738 * code, function code).
57739 *
57740 * The parser uses a traditional top-down recursive parsing for the
57741 * statement level, and an operator precedence based top-down approach
57742 * for the expression level. The attempt is to minimize the C stack
57743 * depth. Bytecode is generated directly without an intermediate
57744 * representation (tree), at the cost of needing two passes over each
57745 * function.
57746 *
57747 * The top-down recursive parser functions are named "duk__parse_XXX".
57748 *
57749 * Recursion limits are in key functions to prevent arbitrary C recursion:
57750 * function body parsing, statement parsing, and expression parsing.
57751 *
57752 * See doc/compiler.rst for discussion on the design.
57753 *
57754 * A few typing notes:
57755 *
57756 * - duk_regconst_t: unsigned, no marker value for "none"
57757 * - duk_reg_t: signed, < 0 = none
57758 * - PC values: duk_int_t, negative values used as markers
57759 */
57760
57761/* include removed: duk_internal.h */
57762
57763/* if highest bit of a register number is set, it refers to a constant instead */
57764#define DUK__CONST_MARKER DUK_JS_CONST_MARKER
57765
57766/* for array and object literals */
57767#define DUK__MAX_ARRAY_INIT_VALUES 20
57768#define DUK__MAX_OBJECT_INIT_PAIRS 10
57769
57770/* XXX: hack, remove when const lookup is not O(n) */
57771#define DUK__GETCONST_MAX_CONSTS_CHECK 256
57772
57773/* These limits are based on bytecode limits. Max temps is limited
57774 * by duk_hcompiledfunction nargs/nregs fields being 16 bits.
57775 */
57776#define DUK__MAX_CONSTS DUK_BC_BC_MAX
57777#define DUK__MAX_FUNCS DUK_BC_BC_MAX
57778#define DUK__MAX_TEMPS 0xffffL
57779
57780/* Initial bytecode size allocation. */
57781#define DUK__BC_INITIAL_INSTS 256
57782
57783#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
57784 DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
57785 duk__recursion_increase((comp_ctx)); \
57786 } while (0)
57787
57788#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
57789 DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
57790 duk__recursion_decrease((comp_ctx)); \
57791 } while (0)
57792
57793/* Value stack slot limits: these are quite approximate right now, and
57794 * because they overlap in control flow, some could be eliminated.
57795 */
57796#define DUK__COMPILE_ENTRY_SLOTS 8
57797#define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16
57798#define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16
57799#define DUK__PARSE_STATEMENTS_SLOTS 16
57800#define DUK__PARSE_EXPR_SLOTS 16
57801
57802/* Temporary structure used to pass a stack allocated region through
57803 * duk_safe_call().
57804 */
57805typedef struct {
57806 duk_small_uint_t flags;
57807 duk_compiler_ctx comp_ctx_alloc;
57808 duk_lexer_point lex_pt_alloc;
57809} duk__compiler_stkstate;
57810
57811/*
57812 * Prototypes
57813 */
57814
57815/* lexing */
57816DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
57817DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
57818DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
57819
57820/* function helpers */
57821DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
57822DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
57823DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg);
57824DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind);
57825DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
57826
57827/* code emission */
57828DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx);
57829DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc);
57830DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins);
57831#if 0 /* unused */
57832DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
57833#endif
57834DUK_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);
57835DUK_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);
57836#if 0 /* unused */
57837DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
57838#endif
57839DUK_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);
57840DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
57841DUK_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);
57842DUK_LOCAL_DECL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b);
57843DUK_LOCAL_DECL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc);
57844DUK_LOCAL_DECL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags);
57845DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
57846DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
57847DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
57848DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
57849DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
57850DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc);
57851DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
57852DUK_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);
57853DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
57854DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
57855DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
57856
57857/* ivalue/ispec helpers */
57858DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
57859DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
57860DUK_LOCAL_DECL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
57861DUK_LOCAL_DECL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
57862DUK_LOCAL_DECL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
57863DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next);
57864DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
57865DUK_LOCAL_DECL
57866duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
57867 duk_ispec *x,
57868 duk_reg_t forced_reg,
57869 duk_small_uint_t flags);
57870DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg);
57871DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg);
57872DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57873DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57874DUK_LOCAL_DECL
57875duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
57876 duk_ivalue *x,
57877 duk_reg_t forced_reg,
57878 duk_small_uint_t flags);
57879DUK_LOCAL_DECL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57880#if 0 /* unused */
57881DUK_LOCAL_DECL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57882#endif
57883DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
57884DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57885DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57886
57887/* identifier handling */
57888DUK_LOCAL_DECL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
57889DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
57890
57891/* label handling */
57892DUK_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);
57893DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
57894DUK_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);
57895DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len);
57896
57897/* top-down expression parser */
57898DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57899DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res);
57900DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx);
57901DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx);
57902
57903/* exprtop is the top level variant which resets nud/led counts */
57904DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57905DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57906
57907/* convenience helpers */
57908#if 0 /* unused */
57909DUK_LOCAL_DECL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57910#endif
57911#if 0 /* unused */
57912DUK_LOCAL_DECL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57913#endif
57914DUK_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);
57915DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57916#if 0 /* unused */
57917DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57918#endif
57919DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57920DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57921DUK_LOCAL_DECL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57922#if 0 /* unused */
57923DUK_LOCAL_DECL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57924#endif
57925DUK_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);
57926DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57927#if 0 /* unused */
57928DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57929#endif
57930
57931/* expression parsing helpers */
57932DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57933DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57934DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57935DUK_LOCAL_DECL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags);
57936
57937/* statement parsing */
57938DUK_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);
57939DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
57940DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57941DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57942DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57943DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57944DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57945DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57946DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57947DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57948DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57949DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57950DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem);
57951DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id);
57952DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof);
57953
57954DUK_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);
57955DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
57956DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget);
57957DUK_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);
57958
57959/*
57960 * Parser control values for tokens. The token table is ordered by the
57961 * DUK_TOK_XXX defines.
57962 *
57963 * The binding powers are for lbp() use (i.e. for use in led() context).
57964 * Binding powers are positive for typing convenience, and bits at the
57965 * top should be reserved for flags. Binding power step must be higher
57966 * than 1 so that binding power "lbp - 1" can be used for right associative
57967 * operators. Currently a step of 2 is used (which frees one more bit for
57968 * flags).
57969 */
57970
57971/* XXX: actually single step levels would work just fine, clean up */
57972
57973/* binding power "levels" (see doc/compiler.rst) */
57974#define DUK__BP_INVALID 0 /* always terminates led() */
57975#define DUK__BP_EOF 2
57976#define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */
57977#define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */
57978#define DUK__BP_COMMA 6
57979#define DUK__BP_ASSIGNMENT 8
57980#define DUK__BP_CONDITIONAL 10
57981#define DUK__BP_LOR 12
57982#define DUK__BP_LAND 14
57983#define DUK__BP_BOR 16
57984#define DUK__BP_BXOR 18
57985#define DUK__BP_BAND 20
57986#define DUK__BP_EQUALITY 22
57987#define DUK__BP_RELATIONAL 24
57988#define DUK__BP_SHIFT 26
57989#define DUK__BP_ADDITIVE 28
57990#define DUK__BP_MULTIPLICATIVE 30
57991#define DUK__BP_POSTFIX 32
57992#define DUK__BP_CALL 34
57993#define DUK__BP_MEMBER 36
57994
57995#define DUK__TOKEN_LBP_BP_MASK 0x1f
57996#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
57997#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
57998#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* spare */
57999
58000#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
58001
58002#define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */
58003#define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags))
58004
58005DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
58006 DUK__MK_LBP(DUK__BP_EOF), /* DUK_TOK_EOF */
58007 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_IDENTIFIER */
58008 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BREAK */
58009 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CASE */
58010 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CATCH */
58011 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONTINUE */
58012 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEBUGGER */
58013 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEFAULT */
58014 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DELETE */
58015 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DO */
58016 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ELSE */
58017 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FINALLY */
58018 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FOR */
58019 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FUNCTION */
58020 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IF */
58021 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_IN */
58022 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_INSTANCEOF */
58023 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_NEW */
58024 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_RETURN */
58025 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SWITCH */
58026 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_THIS */
58027 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_THROW */
58028 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */
58029 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */
58030 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */
58031 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */
58032 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */
58033 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */
58034 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */
58035 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */
58036 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */
58037 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */
58038 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */
58039 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPORT */
58040 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SUPER */
58041 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NULL */
58042 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_TRUE */
58043 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_FALSE */
58044 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_GET */
58045 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SET */
58046 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPLEMENTS */
58047 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_INTERFACE */
58048 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LET */
58049 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PACKAGE */
58050 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PRIVATE */
58051 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PROTECTED */
58052 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PUBLIC */
58053 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_STATIC */
58054 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_YIELD */
58055 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LCURLY */
58056 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RCURLY */
58057 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_LBRACKET */
58058 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RBRACKET */
58059 DUK__MK_LBP(DUK__BP_CALL), /* DUK_TOK_LPAREN */
58060 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RPAREN */
58061 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_PERIOD */
58062 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SEMICOLON */
58063 DUK__MK_LBP(DUK__BP_COMMA), /* DUK_TOK_COMMA */
58064 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LT */
58065 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GT */
58066 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LE */
58067 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GE */
58068 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_EQ */
58069 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_NEQ */
58070 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SEQ */
58071 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SNEQ */
58072 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_ADD */
58073 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_SUB */
58074 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */
58075 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */
58076 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */
58077 DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_INCREMENT */
58078 DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_DECREMENT */
58079 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */
58080 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ARSHIFT */
58081 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_RSHIFT */
58082 DUK__MK_LBP(DUK__BP_BAND), /* DUK_TOK_BAND */
58083 DUK__MK_LBP(DUK__BP_BOR), /* DUK_TOK_BOR */
58084 DUK__MK_LBP(DUK__BP_BXOR), /* DUK_TOK_BXOR */
58085 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LNOT */
58086 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BNOT */
58087 DUK__MK_LBP(DUK__BP_LAND), /* DUK_TOK_LAND */
58088 DUK__MK_LBP(DUK__BP_LOR), /* DUK_TOK_LOR */
58089 DUK__MK_LBP(DUK__BP_CONDITIONAL), /* DUK_TOK_QUESTION */
58090 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_COLON */
58091 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EQUALSIGN */
58092 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ADD_EQ */
58093 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_SUB_EQ */
58094 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */
58095 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */
58096 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */
58097 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */
58098 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */
58099 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */
58100 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */
58101 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */
58102 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */
58103 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */
58104 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */
58105 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */
58106};
58107
58108/*
58109 * Misc helpers
58110 */
58111
58112DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
58113 DUK_ASSERT(comp_ctx != NULL);
58114 DUK_ASSERT(comp_ctx->recursion_depth >= 0);
58115 if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
58116 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT);
58117 }
58118 comp_ctx->recursion_depth++;
58119}
58120
58121DUK_LOCAL void duk__recursion_decrease(duk_compiler_ctx *comp_ctx) {
58122 DUK_ASSERT(comp_ctx != NULL);
58123 DUK_ASSERT(comp_ctx->recursion_depth > 0);
58124 comp_ctx->recursion_depth--;
58125}
58126
58127DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
58128 DUK_UNREF(comp_ctx);
58129 DUK_ASSERT(h != NULL);
58130 return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
58131}
58132
58133DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
58134 DUK_ASSERT(h != NULL);
58135 return (comp_ctx->curr_func.is_strict &&
58136 DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h));
58137}
58138
58139/*
58140 * Parser duk__advance() token eating functions
58141 */
58142
58143/* XXX: valstack handling is awkward. Add a valstack helper which
58144 * avoids dup():ing; valstack_copy(src, dst)?
58145 */
58146
58147DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
58148 duk_hthread *thr = comp_ctx->thr;
58149 duk_context *ctx = (duk_context *) thr;
58150 duk_bool_t regexp;
58151
58152 DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
58153
58154 /*
58155 * Use current token to decide whether a RegExp can follow.
58156 *
58157 * We can use either 't' or 't_nores'; the latter would not
58158 * recognize keywords. Some keywords can be followed by a
58159 * RegExp (e.g. "return"), so using 't' is better. This is
58160 * not trivial, see doc/compiler.rst.
58161 */
58162
58163 regexp = 1;
58164 if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
58165 regexp = 0;
58166 }
58167 if (comp_ctx->curr_func.reject_regexp_in_adv) {
58168 comp_ctx->curr_func.reject_regexp_in_adv = 0;
58169 regexp = 0;
58170 }
58171
58172 if (expect >= 0 && comp_ctx->curr_token.t != expect) {
58173 DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
58174 (long) expect, (long) comp_ctx->curr_token.t));
58175 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
58176 }
58177
58178 /* make current token the previous; need to fiddle with valstack "backing store" */
58179 DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
58180 duk_copy(ctx, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
58181 duk_copy(ctx, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
58182
58183 /* parse new token */
58184 duk_lexer_parse_js_input_element(&comp_ctx->lex,
58185 &comp_ctx->curr_token,
58186 comp_ctx->curr_func.is_strict,
58187 regexp);
58188
58189 DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T "
58190 "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T",
58191 (long) comp_ctx->curr_token.t,
58192 (long) comp_ctx->curr_token.t_nores,
58193 (long) comp_ctx->curr_token.start_line,
58194 (long) comp_ctx->curr_token.lineterm,
58195 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok11_idx),
58196 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok12_idx),
58197 (long) comp_ctx->prev_token.t,
58198 (long) comp_ctx->prev_token.t_nores,
58199 (long) comp_ctx->prev_token.start_line,
58200 (long) comp_ctx->prev_token.lineterm,
58201 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok21_idx),
58202 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok22_idx)));
58203}
58204
58205/* advance, expecting current token to be a specific token; parse next token in regexp context */
58206DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
58207 duk__advance_helper(comp_ctx, expect);
58208}
58209
58210/* advance, whatever the current token is; parse next token in regexp context */
58211DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
58212 duk__advance_helper(comp_ctx, -1);
58213}
58214
58215/*
58216 * Helpers for duk_compiler_func.
58217 */
58218
58219/* init function state: inits valstack allocations */
58220DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
58221 duk_compiler_func *func = &comp_ctx->curr_func;
58222 duk_hthread *thr = comp_ctx->thr;
58223 duk_context *ctx = (duk_context *) thr;
58224 duk_idx_t entry_top;
58225
58226 entry_top = duk_get_top(ctx);
58227
58228 DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
58229#ifdef DUK_USE_EXPLICIT_NULL_INIT
58230 func->h_name = NULL;
58231 func->h_consts = NULL;
58232 func->h_funcs = NULL;
58233 func->h_decls = NULL;
58234 func->h_labelnames = NULL;
58235 func->h_labelinfos = NULL;
58236 func->h_argnames = NULL;
58237 func->h_varmap = NULL;
58238#endif
58239
58240 duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
58241
58242 DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
58243 /* code_idx = entry_top + 0 */
58244
58245 duk_push_array(ctx);
58246 func->consts_idx = entry_top + 1;
58247 func->h_consts = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 1);
58248 DUK_ASSERT(func->h_consts != NULL);
58249
58250 duk_push_array(ctx);
58251 func->funcs_idx = entry_top + 2;
58252 func->h_funcs = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 2);
58253 DUK_ASSERT(func->h_funcs != NULL);
58254 DUK_ASSERT(func->fnum_next == 0);
58255
58256 duk_push_array(ctx);
58257 func->decls_idx = entry_top + 3;
58258 func->h_decls = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 3);
58259 DUK_ASSERT(func->h_decls != NULL);
58260
58261 duk_push_array(ctx);
58262 func->labelnames_idx = entry_top + 4;
58263 func->h_labelnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 4);
58264 DUK_ASSERT(func->h_labelnames != NULL);
58265
58266 duk_push_dynamic_buffer(ctx, 0);
58267 func->labelinfos_idx = entry_top + 5;
58268 func->h_labelinfos = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 5);
58269 DUK_ASSERT(func->h_labelinfos != NULL);
58270 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
58271
58272 duk_push_array(ctx);
58273 func->argnames_idx = entry_top + 6;
58274 func->h_argnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 6);
58275 DUK_ASSERT(func->h_argnames != NULL);
58276
58277 duk_push_object_internal(ctx);
58278 func->varmap_idx = entry_top + 7;
58279 func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 7);
58280 DUK_ASSERT(func->h_varmap != NULL);
58281}
58282
58283/* reset function state (prepare for pass 2) */
58284DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
58285 duk_compiler_func *func = &comp_ctx->curr_func;
58286 duk_hthread *thr = comp_ctx->thr;
58287 duk_context *ctx = (duk_context *) thr;
58288
58289 /* reset bytecode buffer but keep current size; pass 2 will
58290 * require same amount or more.
58291 */
58292 DUK_BW_RESET_SIZE(thr, &func->bw_code);
58293
58294 duk_hobject_set_length_zero(thr, func->h_consts);
58295 /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
58296 func->fnum_next = 0;
58297 /* duk_hobject_set_length_zero(thr, func->h_funcs); */
58298 duk_hobject_set_length_zero(thr, func->h_labelnames);
58299 duk_hbuffer_reset(thr, func->h_labelinfos);
58300 /* keep func->h_argnames; it is fixed for all passes */
58301
58302 /* truncated in case pass 3 needed */
58303 duk_push_object_internal(ctx);
58304 duk_replace(ctx, func->varmap_idx);
58305 func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, func->varmap_idx);
58306 DUK_ASSERT(func->h_varmap != NULL);
58307}
58308
58309/* cleanup varmap from any null entries, compact it, etc; returns number
58310 * of final entries after cleanup.
58311 */
58312DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
58313 duk_hthread *thr = comp_ctx->thr;
58314 duk_context *ctx = (duk_context *) thr;
58315 duk_hobject *h_varmap;
58316 duk_hstring *h_key;
58317 duk_tval *tv;
58318 duk_uint32_t i, e_next;
58319 duk_int_t ret;
58320
58321 /* [ ... varmap ] */
58322
58323 h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
58324 DUK_ASSERT(h_varmap != NULL);
58325
58326 ret = 0;
58327 e_next = DUK_HOBJECT_GET_ENEXT(h_varmap);
58328 for (i = 0; i < e_next; i++) {
58329 h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i);
58330 if (!h_key) {
58331 continue;
58332 }
58333
58334 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i));
58335
58336 /* The entries can either be register numbers or 'null' values.
58337 * Thus, no need to DECREF them and get side effects. DECREF'ing
58338 * the keys (strings) can cause memory to be freed but no side
58339 * effects as strings don't have finalizers. This is why we can
58340 * rely on the object properties not changing from underneath us.
58341 */
58342
58343 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i);
58344 if (!DUK_TVAL_IS_NUMBER(tv)) {
58345 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));
58346 DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL);
58347 DUK_HSTRING_DECREF(thr, h_key);
58348 /* when key is NULL, value is garbage so no need to set */
58349 } else {
58350 ret++;
58351 }
58352 }
58353
58354 duk_compact(ctx, -1);
58355
58356 return ret;
58357}
58358
58359/* convert duk_compiler_func into a function template, leaving the result
58360 * on top of stack.
58361 */
58362/* XXX: awkward and bloated asm -- use faster internal accesses */
58363DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind) {
58364 duk_compiler_func *func = &comp_ctx->curr_func;
58365 duk_hthread *thr = comp_ctx->thr;
58366 duk_context *ctx = (duk_context *) thr;
58367 duk_hcompiledfunction *h_res;
58368 duk_hbuffer_fixed *h_data;
58369 duk_size_t consts_count;
58370 duk_size_t funcs_count;
58371 duk_size_t code_count;
58372 duk_size_t code_size;
58373 duk_size_t data_size;
58374 duk_size_t i;
58375 duk_tval *p_const;
58376 duk_hobject **p_func;
58377 duk_instr_t *p_instr;
58378 duk_compiler_instr *q_instr;
58379 duk_tval *tv;
58380
58381 DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
58382
58383 /*
58384 * Push result object and init its flags
58385 */
58386
58387 /* Valstack should suffice here, required on function valstack init */
58388
58389 (void) duk_push_compiledfunction(ctx);
58390 h_res = (duk_hcompiledfunction *) DUK_GET_HOBJECT_NEGIDX(ctx, -1); /* XXX: specific getter */
58391 DUK_ASSERT(h_res != NULL);
58392
58393 if (func->is_function) {
58394 DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
58395 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
58396
58397 if (!func->is_arguments_shadowed) {
58398 /* arguments object would be accessible; note that shadowing
58399 * bindings are arguments or function declarations, neither
58400 * of which are deletable, so this is safe.
58401 */
58402
58403 if (func->id_access_arguments || func->may_direct_eval) {
58404 DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or "
58405 "indirectly -> set CREATEARGS"));
58406 DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res);
58407 }
58408 }
58409 } else if (func->is_eval && func->is_strict) {
58410 DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV"));
58411 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
58412 } else {
58413 /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
58414 * global code: env is is global env
58415 */
58416 DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV"));
58417 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
58418 }
58419
58420 if (func->is_function && !func->is_decl && func->h_name != NULL && !force_no_namebind) {
58421 /* Object literal set/get functions have a name (property
58422 * name) but must not have a lexical name binding, see
58423 * test-bug-getset-func-name.js.
58424 */
58425 DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
58426 DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
58427 }
58428
58429 if (func->is_strict) {
58430 DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
58431 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
58432 }
58433
58434 if (func->is_notail) {
58435 DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
58436 DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
58437 }
58438
58439 /*
58440 * Build function fixed size 'data' buffer, which contains bytecode,
58441 * constants, and inner function references.
58442 *
58443 * During the building phase 'data' is reachable but incomplete.
58444 * Only incref's occur during building (no refzero or GC happens),
58445 * so the building process is atomic.
58446 */
58447
58448 consts_count = duk_hobject_get_length(thr, func->h_consts);
58449 funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3;
58450 code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr);
58451 code_size = code_count * sizeof(duk_instr_t);
58452
58453 data_size = consts_count * sizeof(duk_tval) +
58454 funcs_count * sizeof(duk_hobject *) +
58455 code_size;
58456
58457 DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> "
58458 "data_size=%ld*%ld + %ld*%ld + %ld = %ld",
58459 (long) consts_count, (long) funcs_count, (long) code_size,
58460 (long) consts_count, (long) sizeof(duk_tval),
58461 (long) funcs_count, (long) sizeof(duk_hobject *),
58462 (long) code_size, (long) data_size));
58463
58464 duk_push_fixed_buffer(ctx, data_size);
58465 h_data = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
58466 DUK_ASSERT(h_data != NULL);
58467
58468 DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
58469 DUK_HEAPHDR_INCREF(thr, h_data);
58470
58471 p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data);
58472 for (i = 0; i < consts_count; i++) {
58473 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* const limits */
58474 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i);
58475 DUK_ASSERT(tv != NULL);
58476 DUK_TVAL_SET_TVAL(p_const, tv);
58477 p_const++;
58478 DUK_TVAL_INCREF(thr, tv); /* may be a string constant */
58479
58480 DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv));
58481 }
58482
58483 p_func = (duk_hobject **) p_const;
58484 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_res, p_func);
58485 for (i = 0; i < funcs_count; i++) {
58486 duk_hobject *h;
58487 DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */
58488 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3));
58489 DUK_ASSERT(tv != NULL);
58490 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
58491 h = DUK_TVAL_GET_OBJECT(tv);
58492 DUK_ASSERT(h != NULL);
58493 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(h));
58494 *p_func++ = h;
58495 DUK_HOBJECT_INCREF(thr, h);
58496
58497 DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
58498 (void *) h, (duk_heaphdr *) h));
58499 }
58500
58501 p_instr = (duk_instr_t *) p_func;
58502 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_res, p_instr);
58503
58504 /* copy bytecode instructions one at a time */
58505 q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code);
58506 for (i = 0; i < code_count; i++) {
58507 p_instr[i] = q_instr[i].ins;
58508 }
58509 /* Note: 'q_instr' is still used below */
58510
58511 DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
58512
58513 duk_pop(ctx); /* 'data' (and everything in it) is reachable through h_res now */
58514
58515 /*
58516 * Init object properties
58517 *
58518 * Properties should be added in decreasing order of access frequency.
58519 * (Not very critical for function templates.)
58520 */
58521
58522 DUK_DDD(DUK_DDDPRINT("init function properties"));
58523
58524 /* [ ... res ] */
58525
58526 /* _Varmap: omitted if function is guaranteed not to do slow path identifier
58527 * accesses or if it would turn out to be empty of actual register mappings
58528 * after a cleanup. When debugging is enabled, we always need the varmap to
58529 * be able to lookup variables at any point.
58530 */
58531#if defined(DUK_USE_DEBUGGER_SUPPORT)
58532 if (1) {
58533#else
58534 if (func->id_access_slow || /* directly uses slow accesses */
58535 func->may_direct_eval || /* may indirectly slow access through a direct eval */
58536 funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
58537#endif
58538 duk_int_t num_used;
58539 duk_dup(ctx, func->varmap_idx);
58540 num_used = duk__cleanup_varmap(comp_ctx);
58541 DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
58542 (duk_tval *) duk_get_tval(ctx, -1), (long) num_used));
58543
58544 if (num_used > 0) {
58545 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
58546 } else {
58547 DUK_DDD(DUK_DDDPRINT("varmap is empty after cleanup -> no need to add"));
58548 duk_pop(ctx);
58549 }
58550 }
58551
58552 /* _Formals: omitted if function is guaranteed not to need a (non-strict) arguments object */
58553 if (1) {
58554 /* XXX: Add a proper condition. If formals list is omitted, recheck
58555 * handling for 'length' in duk_js_push_closure(); it currently relies
58556 * on _Formals being set. Removal may need to be conditional to debugging
58557 * being enabled/disabled too.
58558 */
58559 duk_dup(ctx, func->argnames_idx);
58560 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
58561 }
58562
58563 /* name */
58564 if (func->h_name) {
58565 duk_push_hstring(ctx, func->h_name);
58566 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
58567 }
58568
58569 /* _Source */
58570#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
58571 if (0) {
58572 /* XXX: Currently function source code is not stored, as it is not
58573 * required by the standard. Source code should not be stored by
58574 * default (user should enable it explicitly), and the source should
58575 * probably be compressed with a trivial text compressor; average
58576 * compression of 20-30% is quite easy to achieve even with a trivial
58577 * compressor (RLE + backwards lookup).
58578 *
58579 * Debugging needs source code to be useful: sometimes input code is
58580 * not found in files as it may be generated and then eval()'d, given
58581 * by dynamic C code, etc.
58582 *
58583 * Other issues:
58584 *
58585 * - Need tokenizer indices for start and end to substring
58586 * - Always normalize function declaration part?
58587 * - If we keep _Formals, only need to store body
58588 */
58589
58590 /*
58591 * For global or eval code this is straightforward. For functions
58592 * created with the Function constructor we only get the source for
58593 * the body and must manufacture the "function ..." part.
58594 *
58595 * For instance, for constructed functions (v8):
58596 *
58597 * > a = new Function("foo", "bar", "print(foo)");
58598 * [Function]
58599 * > a.toString()
58600 * 'function anonymous(foo,bar) {\nprint(foo)\n}'
58601 *
58602 * Similarly for e.g. getters (v8):
58603 *
58604 * > x = { get a(foo,bar) { print(foo); } }
58605 * { a: [Getter] }
58606 * > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
58607 * 'function a(foo,bar) { print(foo); }'
58608 */
58609
58610#if 0
58611 duk_push_string(ctx, "XXX");
58612 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
58613#endif
58614 }
58615#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
58616
58617 /* _Pc2line */
58618#if defined(DUK_USE_PC2LINE)
58619 if (1) {
58620 /*
58621 * Size-optimized pc->line mapping.
58622 */
58623
58624 DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
58625 duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */
58626 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
58627
58628 /* XXX: if assertions enabled, walk through all valid PCs
58629 * and check line mapping.
58630 */
58631 }
58632#endif /* DUK_USE_PC2LINE */
58633
58634 /* fileName */
58635 if (comp_ctx->h_filename) {
58636 /*
58637 * Source filename (or equivalent), for identifying thrown errors.
58638 */
58639
58640 duk_push_hstring(ctx, comp_ctx->h_filename);
58641 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
58642 }
58643
58644 /*
58645 * Init remaining result fields
58646 *
58647 * 'nregs' controls how large a register frame is allocated.
58648 *
58649 * 'nargs' controls how many formal arguments are written to registers:
58650 * r0, ... r(nargs-1). The remaining registers are initialized to
58651 * undefined.
58652 */
58653
58654 DUK_ASSERT(func->temp_max >= 0);
58655 h_res->nregs = (duk_uint16_t) func->temp_max;
58656 h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
58657 DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
58658#if defined(DUK_USE_DEBUGGER_SUPPORT)
58659 h_res->start_line = (duk_uint32_t) func->min_line;
58660 h_res->end_line = (duk_uint32_t) func->max_line;
58661#endif
58662
58663 DUK_DD(DUK_DDPRINT("converted function: %!ixT",
58664 (duk_tval *) duk_get_tval(ctx, -1)));
58665
58666 /*
58667 * Compact the function template.
58668 */
58669
58670 duk_compact(ctx, -1);
58671
58672 /*
58673 * Debug dumping
58674 */
58675
58676#ifdef DUK_USE_DDDPRINT
58677 {
58678 duk_hcompiledfunction *h;
58679 duk_instr_t *p, *p_start, *p_end;
58680
58681 h = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
58682 p_start = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, h);
58683 p_end = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, h);
58684
58685 p = p_start;
58686 while (p < p_end) {
58687 DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld",
58688 (long) (p - p_start),
58689 (duk_instr_t) (*p),
58690 (unsigned long) (*p),
58691 (long) DUK_DEC_OP(*p),
58692 (long) DUK_DEC_OP(*p),
58693 (long) DUK_DEC_A(*p),
58694 (long) DUK_DEC_B(*p),
58695 (long) DUK_DEC_C(*p)));
58696 p++;
58697 }
58698 }
58699#endif
58700}
58701
58702/*
58703 * Code emission helpers
58704 *
58705 * Some emission helpers understand the range of target and source reg/const
58706 * values and automatically emit shuffling code if necessary. This is the
58707 * case when the slot in question (A, B, C) is used in the standard way and
58708 * for opcodes the emission helpers explicitly understand (like DUK_OP_CALL).
58709 *
58710 * The standard way is that:
58711 * - slot A is a target register
58712 * - slot B is a source register/constant
58713 * - slot C is a source register/constant
58714 *
58715 * If a slot is used in a non-standard way the caller must indicate this
58716 * somehow. If a slot is used as a target instead of a source (or vice
58717 * versa), this can be indicated with a flag to trigger proper shuffling
58718 * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not
58719 * register/const related at all, the caller must ensure that the raw value
58720 * fits into the corresponding slot so as to not trigger shuffling. The
58721 * caller must set a "no shuffle" flag to ensure compilation fails if
58722 * shuffling were to be triggered because of an internal error.
58723 *
58724 * For slots B and C the raw slot size is 9 bits but one bit is reserved for
58725 * the reg/const indicator. To use the full 9-bit range for a raw value,
58726 * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
58727 * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
58728 *
58729 * There is call handling specific understanding in the A-B-C emitter to
58730 * convert call setup and call instructions into indirect ones if necessary.
58731 */
58732
58733/* Code emission flags, passed in the 'opcode' field. Opcode + flags
58734 * fit into 16 bits for now, so use duk_small_uint.t.
58735 */
58736#define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8)
58737#define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9)
58738#define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10)
58739#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */
58740#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */
58741#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */
58742#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 */
58743#define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
58744
58745/* XXX: clarify on when and where DUK__CONST_MARKER is allowed */
58746/* XXX: opcode specific assertions on when consts are allowed */
58747
58748/* XXX: macro smaller than call? */
58749DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
58750 duk_compiler_func *func;
58751 func = &comp_ctx->curr_func;
58752 return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr));
58753}
58754
58755DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) {
58756 DUK_ASSERT(pc >= 0);
58757 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)));
58758 return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc;
58759}
58760
58761/* emit instruction; could return PC but that's not needed in the majority
58762 * of cases.
58763 */
58764DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
58765#if defined(DUK_USE_PC2LINE)
58766 duk_int_t line;
58767#endif
58768 duk_compiler_instr *instr;
58769
58770 DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I",
58771 (unsigned long) ins,
58772 (long) comp_ctx->curr_token.start_line,
58773 (long) comp_ctx->prev_token.start_line,
58774 (long) duk__get_current_pc(comp_ctx),
58775 (duk_instr_t) ins));
58776
58777 instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
58778 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
58779
58780#if defined(DUK_USE_PC2LINE)
58781 /* The line number tracking is a bit inconsistent right now, which
58782 * affects debugger accuracy. Mostly call sites emit opcodes when
58783 * they have parsed a token (say a terminating semicolon) and called
58784 * duk__advance(). In this case the line number of the previous
58785 * token is the most accurate one (except in prologue where
58786 * prev_token.start_line is 0). This is probably not 100% correct
58787 * right now.
58788 */
58789 /* approximation, close enough */
58790 line = comp_ctx->prev_token.start_line;
58791 if (line == 0) {
58792 line = comp_ctx->curr_token.start_line;
58793 }
58794#endif
58795
58796 instr->ins = ins;
58797#if defined(DUK_USE_PC2LINE)
58798 instr->line = line;
58799#endif
58800#if defined(DUK_USE_DEBUGGER_SUPPORT)
58801 if (line < comp_ctx->curr_func.min_line) {
58802 comp_ctx->curr_func.min_line = line;
58803 }
58804 if (line > comp_ctx->curr_func.max_line) {
58805 comp_ctx->curr_func.max_line = line;
58806 }
58807#endif
58808
58809 /* Limit checks for bytecode byte size and line number. */
58810 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
58811 goto fail_bc_limit;
58812 }
58813#if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS)
58814#if defined(DUK_USE_BUFLEN16)
58815 /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */
58816 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
58817 goto fail_bc_limit;
58818 }
58819#else
58820 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
58821 goto fail_bc_limit;
58822 }
58823#endif
58824#endif
58825
58826 return;
58827
58828 fail_bc_limit:
58829 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
58830}
58831
58832/* Update function min/max line from current token. Needed to improve
58833 * function line range information for debugging, so that e.g. opening
58834 * curly brace is covered by line range even when no opcodes are emitted
58835 * for the line containing the brace.
58836 */
58837DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
58838#if defined(DUK_USE_DEBUGGER_SUPPORT)
58839 duk_int_t line;
58840
58841 line = comp_ctx->curr_token.start_line;
58842 if (line == 0) {
58843 return;
58844 }
58845 if (line < comp_ctx->curr_func.min_line) {
58846 comp_ctx->curr_func.min_line = line;
58847 }
58848 if (line > comp_ctx->curr_func.max_line) {
58849 comp_ctx->curr_func.max_line = line;
58850 }
58851#else
58852 DUK_UNREF(comp_ctx);
58853#endif
58854}
58855
58856#if 0 /* unused */
58857DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) {
58858 duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
58859}
58860#endif
58861
58862/* Important main primitive. */
58863DUK_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) {
58864 duk_instr_t ins = 0;
58865 duk_int_t a_out = -1;
58866 duk_int_t b_out = -1;
58867 duk_int_t c_out = -1;
58868 duk_int_t tmp;
58869
58870 DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
58871 (unsigned long) op_flags, (long) a, (long) b, (long) c));
58872
58873 /* We could rely on max temp/const checks: if they don't exceed BC
58874 * limit, nothing here can either (just asserts would be enough).
58875 * Currently we check for the limits, which provides additional
58876 * protection against creating invalid bytecode due to compiler
58877 * bugs.
58878 */
58879
58880 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
58881 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
58882
58883 /* Input shuffling happens before the actual operation, while output
58884 * shuffling happens afterwards. Output shuffling decisions are still
58885 * made at the same time to reduce branch clutter; output shuffle decisions
58886 * are recorded into X_out variables.
58887 */
58888
58889 /* Slot A */
58890
58891#if defined(DUK_USE_SHUFFLE_TORTURE)
58892 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
58893#else
58894 if (a <= DUK_BC_A_MAX) {
58895#endif
58896 ;
58897 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
58898 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a));
58899 goto error_outofregs;
58900 } else if (a <= DUK_BC_BC_MAX) {
58901 comp_ctx->curr_func.needs_shuffle = 1;
58902 tmp = comp_ctx->curr_func.shuffle1;
58903 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
58904 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
58905 } else {
58906 duk_small_int_t op = op_flags & 0xff;
58907 if (op == DUK_OP_CSVAR || op == DUK_OP_CSREG || op == DUK_OP_CSPROP) {
58908 /* Special handling for call setup instructions. The target
58909 * is expressed indirectly, but there is no output shuffling.
58910 */
58911 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) == 0);
58912 duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
58913 DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1);
58914 DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1);
58915 DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1);
58916 op_flags++; /* indirect opcode follows direct */
58917 } else {
58918 /* Output shuffle needed after main operation */
58919 a_out = a;
58920 }
58921 }
58922 a = tmp;
58923 } else {
58924 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a));
58925 goto error_outofregs;
58926 }
58927
58928 /* Slot B */
58929
58930 if (b & DUK__CONST_MARKER) {
58931 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
58932 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
58933 DUK_ASSERT((op_flags & 0xff) != DUK_OP_CALL);
58934 DUK_ASSERT((op_flags & 0xff) != DUK_OP_NEW);
58935 b = b & ~DUK__CONST_MARKER;
58936#if defined(DUK_USE_SHUFFLE_TORTURE)
58937 if (0) {
58938#else
58939 if (b <= 0xff) {
58940#endif
58941 ins |= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0); /* const flag for B */
58942 } else if (b <= DUK_BC_BC_MAX) {
58943 comp_ctx->curr_func.needs_shuffle = 1;
58944 tmp = comp_ctx->curr_func.shuffle2;
58945 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b));
58946 b = tmp;
58947 } else {
58948 DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b));
58949 goto error_outofregs;
58950 }
58951 } else {
58952#if defined(DUK_USE_SHUFFLE_TORTURE)
58953 if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
58954#else
58955 if (b <= 0xff) {
58956#endif
58957 ;
58958 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
58959 if (b > DUK_BC_B_MAX) {
58960 /* Note: 0xff != DUK_BC_B_MAX */
58961 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b));
58962 goto error_outofregs;
58963 }
58964 } else if (b <= DUK_BC_BC_MAX) {
58965 comp_ctx->curr_func.needs_shuffle = 1;
58966 tmp = comp_ctx->curr_func.shuffle2;
58967 if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) {
58968 /* Output shuffle needed after main operation */
58969 b_out = b;
58970 }
58971 if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET) || (op_flags & DUK__EMIT_FLAG_B_IS_TARGETSOURCE)) {
58972 duk_small_int_t op = op_flags & 0xff;
58973 if (op == DUK_OP_CALL || op == DUK_OP_NEW ||
58974 op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
58975 /* Special handling for CALL/NEW/MPUTOBJ/MPUTARR shuffling.
58976 * For each, slot B identifies the first register of a range
58977 * of registers, so normal shuffling won't work. Instead,
58978 * an indirect version of the opcode is used.
58979 */
58980 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
58981 duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
58982 DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1);
58983 DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1);
58984 DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
58985 DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
58986 op_flags++; /* indirect opcode follows direct */
58987 } else {
58988 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
58989 }
58990 }
58991 b = tmp;
58992 } else {
58993 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b));
58994 goto error_outofregs;
58995 }
58996 }
58997
58998 /* Slot C */
58999
59000 if (c & DUK__CONST_MARKER) {
59001 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
59002 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
59003 c = c & ~DUK__CONST_MARKER;
59004#if defined(DUK_USE_SHUFFLE_TORTURE)
59005 if (0) {
59006#else
59007 if (c <= 0xff) {
59008#endif
59009 ins |= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100); /* const flag for C */
59010 } else if (c <= DUK_BC_BC_MAX) {
59011 comp_ctx->curr_func.needs_shuffle = 1;
59012 tmp = comp_ctx->curr_func.shuffle3;
59013 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c));
59014 c = tmp;
59015 } else {
59016 DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c));
59017 goto error_outofregs;
59018 }
59019 } else {
59020#if defined(DUK_USE_SHUFFLE_TORTURE)
59021 if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
59022#else
59023 if (c <= 0xff) {
59024#endif
59025 ;
59026 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
59027 if (c > DUK_BC_C_MAX) {
59028 /* Note: 0xff != DUK_BC_C_MAX */
59029 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c));
59030 goto error_outofregs;
59031 }
59032 } else if (c <= DUK_BC_BC_MAX) {
59033 comp_ctx->curr_func.needs_shuffle = 1;
59034 tmp = comp_ctx->curr_func.shuffle3;
59035 if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) {
59036 /* Output shuffle needed after main operation */
59037 c_out = c;
59038 } else {
59039 duk_small_int_t op = op_flags & 0xff;
59040 if (op == DUK_OP_EXTRA &&
59041 (a == DUK_EXTRAOP_INITGET || a == DUK_EXTRAOP_INITSET)) {
59042 /* Special shuffling for INITGET/INITSET, where slot C
59043 * identifies a register pair and cannot be shuffled
59044 * normally. Use an indirect variant instead.
59045 */
59046 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
59047 duk__emit_load_int32_noshuffle(comp_ctx, tmp, c);
59048 DUK_ASSERT(DUK_EXTRAOP_INITGETI == DUK_EXTRAOP_INITGET + 1);
59049 DUK_ASSERT(DUK_EXTRAOP_INITSETI == DUK_EXTRAOP_INITSET + 1);
59050 a++; /* indirect opcode follows direct */
59051 } else {
59052 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
59053 }
59054 }
59055 c = tmp;
59056 } else {
59057 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c));
59058 goto error_outofregs;
59059 }
59060 }
59061
59062 /* Main operation */
59063
59064 DUK_ASSERT_DISABLE(a >= DUK_BC_A_MIN); /* unsigned */
59065 DUK_ASSERT(a <= DUK_BC_A_MAX);
59066 DUK_ASSERT_DISABLE(b >= DUK_BC_B_MIN); /* unsigned */
59067 DUK_ASSERT(b <= DUK_BC_B_MAX);
59068 DUK_ASSERT_DISABLE(c >= DUK_BC_C_MIN); /* unsigned */
59069 DUK_ASSERT(c <= DUK_BC_C_MAX);
59070
59071 ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
59072 duk__emit(comp_ctx, ins);
59073
59074 /* NEXTENUM needs a jump slot right after the main instruction.
59075 * When the JUMP is taken, output spilling is not needed so this
59076 * workaround is possible. The jump slot PC is exceptionally
59077 * plumbed through comp_ctx to minimize call sites.
59078 */
59079 if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) {
59080 comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx);
59081 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
59082 }
59083
59084 /* Output shuffling: only one output register is realistically possible.
59085 *
59086 * (Zero would normally be an OK marker value: if the target register
59087 * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE
59088 * this is no longer true, so use -1 as a marker instead.)
59089 */
59090
59091 if (a_out >= 0) {
59092 DUK_ASSERT(b_out < 0);
59093 DUK_ASSERT(c_out < 0);
59094 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
59095 } else if (b_out >= 0) {
59096 DUK_ASSERT(a_out < 0);
59097 DUK_ASSERT(c_out < 0);
59098 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
59099 } else if (c_out >= 0) {
59100 DUK_ASSERT(b_out < 0);
59101 DUK_ASSERT(c_out < 0);
59102 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
59103 }
59104
59105 return;
59106
59107 error_outofregs:
59108 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
59109}
59110
59111DUK_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) {
59112 duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, b, 0);
59113}
59114
59115#if 0 /* unused */
59116DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
59117 duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, 0, 0);
59118}
59119#endif
59120
59121DUK_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) {
59122 duk_instr_t ins;
59123 duk_int_t tmp;
59124
59125 /* allow caller to give a const number with the DUK__CONST_MARKER */
59126 bc = bc & (~DUK__CONST_MARKER);
59127
59128 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
59129 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
59130 DUK_ASSERT_DISABLE(bc >= DUK_BC_BC_MIN); /* unsigned */
59131 DUK_ASSERT(bc <= DUK_BC_BC_MAX);
59132 DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
59133
59134 if (bc <= DUK_BC_BC_MAX) {
59135 ;
59136 } else {
59137 /* No BC shuffling now. */
59138 goto error_outofregs;
59139 }
59140
59141#if defined(DUK_USE_SHUFFLE_TORTURE)
59142 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
59143#else
59144 if (a <= DUK_BC_A_MAX) {
59145#endif
59146 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
59147 duk__emit(comp_ctx, ins);
59148 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
59149 goto error_outofregs;
59150 } else if (a <= DUK_BC_BC_MAX) {
59151 comp_ctx->curr_func.needs_shuffle = 1;
59152 tmp = comp_ctx->curr_func.shuffle1;
59153 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
59154 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
59155 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
59156 duk__emit(comp_ctx, ins);
59157 } else {
59158 duk__emit(comp_ctx, ins);
59159 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
59160 }
59161 } else {
59162 goto error_outofregs;
59163 }
59164 return;
59165
59166 error_outofregs:
59167 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
59168}
59169
59170DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
59171 duk_instr_t ins;
59172
59173 DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN); /* unsigned */
59174 DUK_ASSERT(op <= DUK_BC_OP_MAX);
59175 DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */
59176 DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
59177 DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
59178
59179 if (abc <= DUK_BC_ABC_MAX) {
59180 ;
59181 } else {
59182 goto error_outofregs;
59183 }
59184 ins = DUK_ENC_OP_ABC(op, abc);
59185 DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!C) abc=%ld (%!I)",
59186 (unsigned long) ins, (long) comp_ctx->curr_token.start_line,
59187 (long) duk__get_current_pc(comp_ctx), (long) op, (long) op,
59188 (long) abc, (duk_instr_t) ins));
59189 duk__emit(comp_ctx, ins);
59190 return;
59191
59192 error_outofregs:
59193 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
59194}
59195
59196DUK_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) {
59197 DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59198 DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
59199 /* Setting "no shuffle A" is covered by the assert, but it's needed
59200 * with DUK_USE_SHUFFLE_TORTURE.
59201 */
59202 duk__emit_a_b_c(comp_ctx,
59203 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
59204 extraop_flags & 0xff,
59205 b,
59206 c);
59207}
59208
59209DUK_LOCAL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b) {
59210 DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59211 DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
59212 /* Setting "no shuffle A" is covered by the assert, but it's needed
59213 * with DUK_USE_SHUFFLE_TORTURE.
59214 */
59215 duk__emit_a_b_c(comp_ctx,
59216 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
59217 extraop_flags & 0xff,
59218 b,
59219 0);
59220}
59221
59222DUK_LOCAL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc) {
59223 DUK_ASSERT_DISABLE(extraop >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59224 DUK_ASSERT(extraop <= DUK_BC_EXTRAOP_MAX);
59225 /* Setting "no shuffle A" is covered by the assert, but it's needed
59226 * with DUK_USE_SHUFFLE_TORTURE.
59227 */
59228 duk__emit_a_bc(comp_ctx,
59229 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A,
59230 extraop,
59231 bc);
59232}
59233
59234DUK_LOCAL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags) {
59235 DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59236 DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
59237 /* Setting "no shuffle A" is covered by the assert, but it's needed
59238 * with DUK_USE_SHUFFLE_TORTURE.
59239 */
59240 duk__emit_a_b_c(comp_ctx,
59241 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B |
59242 DUK__EMIT_FLAG_NO_SHUFFLE_C | (extraop_flags & ~0xff), /* transfer flags */
59243 extraop_flags & 0xff,
59244 0,
59245 0);
59246}
59247
59248DUK_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) {
59249 /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
59250 * would only shuffle once (instead of twice). The current code works
59251 * though, and has a smaller compiler footprint.
59252 */
59253
59254 if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
59255 (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
59256 DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val));
59257 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
59258 } else {
59259 duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
59260 duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
59261 DUK_ASSERT(lo >= 0);
59262 DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
59263 (long) reg, (long) val, (long) hi, (long) lo));
59264 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
59265 duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo);
59266 }
59267}
59268
59269DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
59270 duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
59271}
59272
59273#if defined(DUK_USE_SHUFFLE_TORTURE)
59274/* Used by duk__emit*() calls so that we don't shuffle the loadints that
59275 * are needed to handle indirect opcodes.
59276 */
59277DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
59278 duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
59279}
59280#else
59281DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
59282 /* When torture not enabled, can just use the same helper because
59283 * 'reg' won't get spilled.
59284 */
59285 DUK_ASSERT(reg <= DUK_BC_A_MAX);
59286 duk__emit_load_int32(comp_ctx, reg, val);
59287}
59288#endif
59289
59290DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
59291 duk_int_t curr_pc;
59292 duk_int_t offset;
59293
59294 curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
59295 offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1;
59296 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN);
59297 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX);
59298 duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS));
59299}
59300
59301DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
59302 duk_int_t ret;
59303
59304 ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */
59305 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
59306 return ret;
59307}
59308
59309/* Insert an empty jump in the middle of code emitted earlier. This is
59310 * currently needed for compiling for-in.
59311 */
59312DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
59313#if defined(DUK_USE_PC2LINE)
59314 duk_int_t line;
59315#endif
59316 duk_compiler_instr *instr;
59317 duk_size_t offset;
59318
59319 offset = jump_pc * sizeof(duk_compiler_instr),
59320 instr = (duk_compiler_instr *) (void *)
59321 DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
59322 &comp_ctx->curr_func.bw_code,
59323 offset,
59324 sizeof(duk_compiler_instr));
59325
59326#if defined(DUK_USE_PC2LINE)
59327 line = comp_ctx->curr_token.start_line; /* approximation, close enough */
59328#endif
59329 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
59330#if defined(DUK_USE_PC2LINE)
59331 instr->line = line;
59332#endif
59333
59334 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
59335 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
59336 goto fail_bc_limit;
59337 }
59338 return;
59339
59340 fail_bc_limit:
59341 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
59342}
59343
59344/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
59345 * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
59346 */
59347DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) {
59348 duk_compiler_instr *instr;
59349 duk_int_t offset;
59350
59351 /* allow negative PCs, behave as a no-op */
59352 if (jump_pc < 0) {
59353 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
59354 (long) jump_pc, (long) target_pc));
59355 return;
59356 }
59357 DUK_ASSERT(jump_pc >= 0);
59358
59359 /* XXX: range assert */
59360 instr = duk__get_instr_ptr(comp_ctx, jump_pc);
59361 DUK_ASSERT(instr != NULL);
59362
59363 /* XXX: range assert */
59364 offset = target_pc - jump_pc - 1;
59365
59366 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
59367 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld",
59368 (long) jump_pc, (long) target_pc, (long) offset));
59369}
59370
59371DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
59372 duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx));
59373}
59374
59375DUK_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) {
59376 duk_compiler_instr *instr;
59377
59378 DUK_ASSERT((reg_catch & DUK__CONST_MARKER) == 0);
59379
59380 instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
59381 DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
59382 DUK_ASSERT(instr != NULL);
59383 if (const_varname & DUK__CONST_MARKER) {
59384 /* Have a catch variable. */
59385 const_varname = const_varname & (~DUK__CONST_MARKER);
59386 if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) {
59387 /* Catch attempts to use out-of-range reg/const. Without this
59388 * check Duktape 0.12.0 could generate invalid code which caused
59389 * an assert failure on execution. This error is triggered e.g.
59390 * for functions with a lot of constants and a try-catch statement.
59391 * Shuffling or opcode semantics change is needed to fix the issue.
59392 * See: test-bug-trycatch-many-constants.js.
59393 */
59394 DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
59395 (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname));
59396 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
59397 }
59398 instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
59399 } else {
59400 /* No catch variable, e.g. a try-finally; replace LDCONST with
59401 * NOP to avoid a bogus LDCONST.
59402 */
59403 instr->ins = DUK_ENC_OP_A(DUK_OP_EXTRA, DUK_EXTRAOP_NOP);
59404 }
59405
59406 instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
59407 DUK_ASSERT(instr != NULL);
59408 DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN);
59409 DUK_ASSERT(flags <= DUK_BC_A_MAX);
59410 instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch);
59411}
59412
59413DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
59414 duk__emit_a_b_c(comp_ctx,
59415 DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
59416 0 /*false*/,
59417 regconst,
59418 0 /*unused*/);
59419}
59420
59421DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
59422 duk__emit_a_b_c(comp_ctx,
59423 DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
59424 1 /*true*/,
59425 regconst,
59426 0 /*unused*/);
59427}
59428
59429DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
59430 duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_INVALID, 0);
59431}
59432
59433/*
59434 * Peephole optimizer for finished bytecode.
59435 *
59436 * Does not remove opcodes; currently only straightens out unconditional
59437 * jump chains which are generated by several control structures.
59438 */
59439
59440DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
59441 duk_compiler_instr *bc;
59442 duk_small_uint_t iter;
59443 duk_int_t i, n;
59444 duk_int_t count_opt;
59445
59446 bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code);
59447#if defined(DUK_USE_BUFLEN16)
59448 /* No need to assert, buffer size maximum is 0xffff. */
59449#else
59450 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 */
59451#endif
59452 n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
59453
59454 for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
59455 count_opt = 0;
59456
59457 for (i = 0; i < n; i++) {
59458 duk_instr_t ins;
59459 duk_int_t target_pc1;
59460 duk_int_t target_pc2;
59461
59462 ins = bc[i].ins;
59463 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
59464 continue;
59465 }
59466
59467 target_pc1 = i + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
59468 DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
59469 DUK_ASSERT(target_pc1 >= 0);
59470 DUK_ASSERT(target_pc1 < n);
59471
59472 /* Note: if target_pc1 == i, we'll optimize a jump to itself.
59473 * This does not need to be checked for explicitly; the case
59474 * is rare and max iter breaks us out.
59475 */
59476
59477 ins = bc[target_pc1].ins;
59478 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
59479 continue;
59480 }
59481
59482 target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
59483
59484 DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
59485 (long) i, (long) target_pc1, (long) target_pc2));
59486
59487 bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
59488
59489 count_opt++;
59490 }
59491
59492 DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1)));
59493
59494 if (count_opt == 0) {
59495 break;
59496 }
59497 }
59498}
59499
59500/*
59501 * Intermediate value helpers
59502 */
59503
59504#define DUK__ISREG(comp_ctx,x) (((x) & DUK__CONST_MARKER) == 0)
59505#define DUK__ISCONST(comp_ctx,x) (((x) & DUK__CONST_MARKER) != 0)
59506#define DUK__ISTEMP(comp_ctx,x) (DUK__ISREG((comp_ctx), (x)) && (duk_regconst_t) (x) >= (duk_regconst_t) ((comp_ctx)->curr_func.temp_first))
59507#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
59508#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
59509#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
59510#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
59511#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
59512
59513/* Flags for intermediate value coercions. A flag for using a forced reg
59514 * is not needed, the forced_reg argument suffices and generates better
59515 * code (it is checked as it is used).
59516 */
59517#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
59518#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
59519#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
59520
59521/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
59522
59523#if 0 /* enable manually for dumping */
59524#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
59525#define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0)
59526
59527DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
59528 DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
59529 (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
59530 duk_get_tval((duk_context *) comp_ctx->thr, x->valstack_idx)));
59531}
59532DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
59533 DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
59534 "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} "
59535 "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
59536 (long) x->t, (long) x->op,
59537 (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
59538 duk_get_tval((duk_context *) comp_ctx->thr, x->x1.valstack_idx),
59539 (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
59540 duk_get_tval((duk_context *) comp_ctx->thr, x->x2.valstack_idx)));
59541}
59542#else
59543#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
59544#define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
59545#endif
59546
59547DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
59548 duk_context *ctx = (duk_context *) comp_ctx->thr;
59549
59550 dst->t = src->t;
59551 dst->regconst = src->regconst;
59552 duk_copy(ctx, src->valstack_idx, dst->valstack_idx);
59553}
59554
59555DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
59556 duk_context *ctx = (duk_context *) comp_ctx->thr;
59557
59558 dst->t = src->t;
59559 dst->op = src->op;
59560 dst->x1.t = src->x1.t;
59561 dst->x1.regconst = src->x1.regconst;
59562 dst->x2.t = src->x2.t;
59563 dst->x2.regconst = src->x2.regconst;
59564 duk_copy(ctx, src->x1.valstack_idx, dst->x1.valstack_idx);
59565 duk_copy(ctx, src->x2.valstack_idx, dst->x2.valstack_idx);
59566}
59567
59568/* XXX: to util */
59569DUK_LOCAL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
59570 duk_small_int_t c;
59571 duk_int32_t t;
59572
59573 c = DUK_FPCLASSIFY(x);
59574 if (c == DUK_FP_NORMAL || (c == DUK_FP_ZERO && !DUK_SIGNBIT(x))) {
59575 /* Don't allow negative zero as it will cause trouble with
59576 * LDINT+LDINTX. But positive zero is OK.
59577 */
59578 t = (duk_int32_t) x;
59579 if ((duk_double_t) t == x) {
59580 *ival = t;
59581 return 1;
59582 }
59583 }
59584
59585 return 0;
59586}
59587
59588DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
59589 duk_reg_t res;
59590
59591 res = comp_ctx->curr_func.temp_next;
59592 comp_ctx->curr_func.temp_next += num;
59593
59594 if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */
59595 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT);
59596 }
59597
59598 /* maintain highest 'used' temporary, needed to figure out nregs of function */
59599 if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) {
59600 comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next;
59601 }
59602
59603 return res;
59604}
59605
59606DUK_LOCAL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
59607 return duk__alloctemps(comp_ctx, 1);
59608}
59609
59610DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next) {
59611 comp_ctx->curr_func.temp_next = temp_next;
59612 if (temp_next > comp_ctx->curr_func.temp_max) {
59613 comp_ctx->curr_func.temp_max = temp_next;
59614 }
59615}
59616
59617/* get const for value at valstack top */
59618DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
59619 duk_hthread *thr = comp_ctx->thr;
59620 duk_context *ctx = (duk_context *) thr;
59621 duk_compiler_func *f = &comp_ctx->curr_func;
59622 duk_tval *tv1;
59623 duk_int_t i, n, n_check;
59624
59625 n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
59626
59627 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
59628 DUK_ASSERT(tv1 != NULL);
59629
59630#if defined(DUK_USE_FASTINT)
59631 /* Explicit check for fastint downgrade. */
59632 DUK_TVAL_CHKFAST_INPLACE(tv1);
59633#endif
59634
59635 /* Sanity workaround for handling functions with a large number of
59636 * constants at least somewhat reasonably. Otherwise checking whether
59637 * we already have the constant would grow very slow (as it is O(N^2)).
59638 */
59639 n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n);
59640 for (i = 0; i < n_check; i++) {
59641 duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i);
59642
59643 /* Strict equality is NOT enough, because we cannot use the same
59644 * constant for e.g. +0 and -0.
59645 */
59646 if (duk_js_samevalue(tv1, tv2)) {
59647 DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
59648 (duk_tval *) tv1, (long) i));
59649 duk_pop(ctx);
59650 return (duk_regconst_t) (i | DUK__CONST_MARKER);
59651 }
59652 }
59653
59654 if (n > DUK__MAX_CONSTS) {
59655 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
59656 }
59657
59658 DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
59659 (duk_tval *) tv1, (long) n));
59660 (void) duk_put_prop_index(ctx, f->consts_idx, n); /* invalidates tv1, tv2 */
59661 return (duk_regconst_t) (n | DUK__CONST_MARKER);
59662}
59663
59664/* Get the value represented by an duk_ispec to a register or constant.
59665 * The caller can control the result by indicating whether or not:
59666 *
59667 * (1) a constant is allowed (sometimes the caller needs the result to
59668 * be in a register)
59669 *
59670 * (2) a temporary register is required (usually when caller requires
59671 * the register to be safely mutable; normally either a bound
59672 * register or a temporary register are both OK)
59673 *
59674 * (3) a forced register target needs to be used
59675 *
59676 * Bytecode may be emitted to generate the necessary value. The return
59677 * value is either a register or a constant.
59678 */
59679
59680DUK_LOCAL
59681duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
59682 duk_ispec *x,
59683 duk_reg_t forced_reg,
59684 duk_small_uint_t flags) {
59685 duk_hthread *thr = comp_ctx->thr;
59686 duk_context *ctx = (duk_context *) thr;
59687
59688 DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
59689 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
59690 (long) x->t,
59691 (long) x->regconst,
59692 (duk_tval *) duk_get_tval(ctx, x->valstack_idx),
59693 (long) forced_reg,
59694 (unsigned long) flags,
59695 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
59696 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
59697 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
59698
59699 switch (x->t) {
59700 case DUK_ISPEC_VALUE: {
59701 duk_tval *tv;
59702
59703 tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
59704 DUK_ASSERT(tv != NULL);
59705
59706 switch (DUK_TVAL_GET_TAG(tv)) {
59707 case DUK_TAG_UNDEFINED: {
59708 /* Note: although there is no 'undefined' literal, undefined
59709 * values can occur during compilation as a result of e.g.
59710 * the 'void' operator.
59711 */
59712 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59713 duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, (duk_regconst_t) dest);
59714 return (duk_regconst_t) dest;
59715 }
59716 case DUK_TAG_NULL: {
59717 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59718 duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDNULL, (duk_regconst_t) dest);
59719 return (duk_regconst_t) dest;
59720 }
59721 case DUK_TAG_BOOLEAN: {
59722 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59723 duk__emit_extraop_bc(comp_ctx,
59724 (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_EXTRAOP_LDTRUE : DUK_EXTRAOP_LDFALSE),
59725 (duk_regconst_t) dest);
59726 return (duk_regconst_t) dest;
59727 }
59728 case DUK_TAG_POINTER: {
59729 DUK_UNREACHABLE();
59730 break;
59731 }
59732 case DUK_TAG_STRING: {
59733 duk_hstring *h;
59734 duk_reg_t dest;
59735 duk_regconst_t constidx;
59736
59737 h = DUK_TVAL_GET_STRING(tv);
59738 DUK_UNREF(h);
59739 DUK_ASSERT(h != NULL);
59740
59741#if 0 /* XXX: to be implemented? */
59742 /* Use special opcodes to load short strings */
59743 if (DUK_HSTRING_GET_BYTELEN(h) <= 2) {
59744 /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
59745 } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) {
59746 /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
59747 }
59748#endif
59749 duk_dup(ctx, x->valstack_idx);
59750 constidx = duk__getconst(comp_ctx);
59751
59752 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
59753 return constidx;
59754 }
59755
59756 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59757 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
59758 return (duk_regconst_t) dest;
59759 }
59760 case DUK_TAG_OBJECT: {
59761 DUK_UNREACHABLE();
59762 break;
59763 }
59764 case DUK_TAG_BUFFER: {
59765 DUK_UNREACHABLE();
59766 break;
59767 }
59768 case DUK_TAG_LIGHTFUNC: {
59769 DUK_UNREACHABLE();
59770 break;
59771 }
59772#if defined(DUK_USE_FASTINT)
59773 case DUK_TAG_FASTINT:
59774#endif
59775 default: {
59776 /* number */
59777 duk_reg_t dest;
59778 duk_regconst_t constidx;
59779 duk_double_t dval;
59780 duk_int32_t ival;
59781
59782 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
59783 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
59784 dval = DUK_TVAL_GET_NUMBER(tv);
59785
59786 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
59787 /* A number can be loaded either through a constant, using
59788 * LDINT, or using LDINT+LDINTX. LDINT is always a size win,
59789 * LDINT+LDINTX is not if the constant is used multiple times.
59790 * Currently always prefer LDINT+LDINTX over a double constant.
59791 */
59792
59793 if (duk__is_whole_get_int32(dval, &ival)) {
59794 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59795 duk__emit_load_int32(comp_ctx, dest, ival);
59796 return (duk_regconst_t) dest;
59797 }
59798 }
59799
59800 duk_dup(ctx, x->valstack_idx);
59801 constidx = duk__getconst(comp_ctx);
59802
59803 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
59804 return constidx;
59805 } else {
59806 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59807 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
59808 return (duk_regconst_t) dest;
59809 }
59810 }
59811 } /* end switch */
59812 }
59813 case DUK_ISPEC_REGCONST: {
59814 if (forced_reg >= 0) {
59815 if (x->regconst & DUK__CONST_MARKER) {
59816 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
59817 } else if (x->regconst != (duk_regconst_t) forced_reg) {
59818 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
59819 } else {
59820 ; /* already in correct reg */
59821 }
59822 return (duk_regconst_t) forced_reg;
59823 }
59824
59825 DUK_ASSERT(forced_reg < 0);
59826 if (x->regconst & DUK__CONST_MARKER) {
59827 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
59828 duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
59829 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, x->regconst);
59830 return (duk_regconst_t) dest;
59831 }
59832 return x->regconst;
59833 }
59834
59835 DUK_ASSERT(forced_reg < 0 && !(x->regconst & DUK__CONST_MARKER));
59836 if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISTEMP(comp_ctx, x->regconst)) {
59837 duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
59838 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, (duk_regconst_t) dest, x->regconst);
59839 return (duk_regconst_t) dest;
59840 }
59841 return x->regconst;
59842 }
59843 default: {
59844 break;
59845 }
59846 }
59847
59848 DUK_ERROR_INTERNAL_DEFMSG(thr);
59849 return 0;
59850}
59851
59852DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg) {
59853 DUK_ASSERT(forced_reg >= 0);
59854 (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
59855}
59856
59857/* Coerce an duk_ivalue to a 'plain' value by generating the necessary
59858 * arithmetic operations, property access, or variable access bytecode.
59859 * The duk_ivalue argument ('x') is converted into a plain value as a
59860 * side effect.
59861 */
59862DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg) {
59863 duk_hthread *thr = comp_ctx->thr;
59864 duk_context *ctx = (duk_context *) thr;
59865
59866 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
59867 "forced_reg=%ld",
59868 (long) x->t, (long) x->op,
59869 (long) x->x1.t, (long) x->x1.regconst,
59870 (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
59871 (long) x->x2.t, (long) x->x2.regconst,
59872 (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
59873 (long) forced_reg));
59874
59875 switch (x->t) {
59876 case DUK_IVAL_PLAIN: {
59877 return;
59878 }
59879 /* XXX: support unary arithmetic ivalues (useful?) */
59880 case DUK_IVAL_ARITH:
59881 case DUK_IVAL_ARITH_EXTRAOP: {
59882 duk_regconst_t arg1;
59883 duk_regconst_t arg2;
59884 duk_reg_t dest;
59885 duk_tval *tv1;
59886 duk_tval *tv2;
59887
59888 DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
59889
59890 /* inline arithmetic check for constant values */
59891 /* XXX: use the exactly same arithmetic function here as in executor */
59892 if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
59893 tv1 = DUK_GET_TVAL_POSIDX(ctx, x->x1.valstack_idx);
59894 tv2 = DUK_GET_TVAL_POSIDX(ctx, x->x2.valstack_idx);
59895 DUK_ASSERT(tv1 != NULL);
59896 DUK_ASSERT(tv2 != NULL);
59897
59898 DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
59899 (duk_tval *) tv1,
59900 (duk_tval *) tv2));
59901
59902 if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) {
59903 duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1);
59904 duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2);
59905 duk_double_t d3;
59906 duk_bool_t accept = 1;
59907
59908 DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
59909 (double) d1, (double) d2, (long) x->op));
59910 switch (x->op) {
59911 case DUK_OP_ADD: d3 = d1 + d2; break;
59912 case DUK_OP_SUB: d3 = d1 - d2; break;
59913 case DUK_OP_MUL: d3 = d1 * d2; break;
59914 case DUK_OP_DIV: d3 = d1 / d2; break;
59915 default: accept = 0; break;
59916 }
59917
59918 if (accept) {
59919 duk_double_union du;
59920 du.d = d3;
59921 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
59922 d3 = du.d;
59923
59924 x->t = DUK_IVAL_PLAIN;
59925 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
59926 DUK_TVAL_SET_NUMBER(tv1, d3); /* old value is number: no refcount */
59927 return;
59928 }
59929 } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
59930 /* inline string concatenation */
59931 duk_dup(ctx, x->x1.valstack_idx);
59932 duk_dup(ctx, x->x2.valstack_idx);
59933 duk_concat(ctx, 2);
59934 duk_replace(ctx, x->x1.valstack_idx);
59935 x->t = DUK_IVAL_PLAIN;
59936 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
59937 return;
59938 }
59939 }
59940
59941 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
59942 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
59943
59944 /* If forced reg, use it as destination. Otherwise try to
59945 * use either coerced ispec if it is a temporary.
59946 *
59947 * When using extraops, avoid reusing arg2 as dest because that
59948 * would lead to an LDREG shuffle below. We still can't guarantee
59949 * dest != arg2 because we may have a forced_reg.
59950 */
59951 if (forced_reg >= 0) {
59952 dest = forced_reg;
59953 } else if (DUK__ISTEMP(comp_ctx, arg1)) {
59954 dest = (duk_reg_t) arg1;
59955 } else if (DUK__ISTEMP(comp_ctx, arg2) && x->t != DUK_IVAL_ARITH_EXTRAOP) {
59956 dest = (duk_reg_t) arg2;
59957 } else {
59958 dest = DUK__ALLOCTEMP(comp_ctx);
59959 }
59960
59961 /* Extraop arithmetic opcodes must have destination same as
59962 * first source. If second source matches destination we need
59963 * a temporary register to avoid clobbering the second source.
59964 *
59965 * XXX: change calling code to avoid this situation in most cases.
59966 */
59967
59968 if (x->t == DUK_IVAL_ARITH_EXTRAOP) {
59969 if (!(DUK__ISREG(comp_ctx, arg1) && (duk_reg_t) arg1 == dest)) {
59970 if (DUK__ISREG(comp_ctx, arg2) && (duk_reg_t) arg2 == dest) {
59971 /* arg2 would be clobbered so reassign it to a temp. */
59972 duk_reg_t tempreg;
59973 tempreg = DUK__ALLOCTEMP(comp_ctx);
59974 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, tempreg, arg2);
59975 arg2 = tempreg;
59976 }
59977
59978 if (DUK__ISREG(comp_ctx, arg1)) {
59979 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, arg1);
59980 } else {
59981 DUK_ASSERT(DUK__ISCONST(comp_ctx, arg1));
59982 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, arg1);
59983 }
59984 }
59985
59986 /* Note: special DUK__EMIT_FLAG_B_IS_TARGETSOURCE
59987 * used to indicate that B is both a source and a
59988 * target register. When shuffled, it needs to be
59989 * both input and output shuffled.
59990 */
59991 DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
59992 duk__emit_extraop_b_c(comp_ctx,
59993 x->op | DUK__EMIT_FLAG_B_IS_TARGET |
59994 DUK__EMIT_FLAG_B_IS_TARGETSOURCE,
59995 (duk_regconst_t) dest,
59996 (duk_regconst_t) arg2);
59997
59998 } else {
59999 DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
60000 duk__emit_a_b_c(comp_ctx, x->op, (duk_regconst_t) dest, arg1, arg2);
60001 }
60002
60003 x->t = DUK_IVAL_PLAIN;
60004 x->x1.t = DUK_ISPEC_REGCONST;
60005 x->x1.regconst = (duk_regconst_t) dest;
60006 return;
60007 }
60008 case DUK_IVAL_PROP: {
60009 /* XXX: very similar to DUK_IVAL_ARITH - merge? */
60010 duk_regconst_t arg1;
60011 duk_regconst_t arg2;
60012 duk_reg_t dest;
60013
60014 /* Need a short reg/const, does not have to be a mutable temp. */
60015 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
60016 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
60017
60018 /* Pick a destination register. If either base value or key
60019 * happens to be a temp value, reuse it as the destination.
60020 *
60021 * XXX: The temp must be a "mutable" one, i.e. such that no
60022 * other expression is using it anymore. Here this should be
60023 * the case because the value of a property access expression
60024 * is neither the base nor the key, but the lookup result.
60025 */
60026
60027 if (forced_reg >= 0) {
60028 dest = forced_reg;
60029 } else if (DUK__ISTEMP(comp_ctx, arg1)) {
60030 dest = (duk_reg_t) arg1;
60031 } else if (DUK__ISTEMP(comp_ctx, arg2)) {
60032 dest = (duk_reg_t) arg2;
60033 } else {
60034 dest = DUK__ALLOCTEMP(comp_ctx);
60035 }
60036
60037 duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, (duk_regconst_t) dest, arg1, arg2);
60038
60039 x->t = DUK_IVAL_PLAIN;
60040 x->x1.t = DUK_ISPEC_REGCONST;
60041 x->x1.regconst = (duk_regconst_t) dest;
60042 return;
60043 }
60044 case DUK_IVAL_VAR: {
60045 /* x1 must be a string */
60046 duk_reg_t dest;
60047 duk_reg_t reg_varbind;
60048 duk_regconst_t rc_varname;
60049
60050 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
60051
60052 duk_dup(ctx, x->x1.valstack_idx);
60053 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
60054 x->t = DUK_IVAL_PLAIN;
60055 x->x1.t = DUK_ISPEC_REGCONST;
60056 x->x1.regconst = (duk_regconst_t) reg_varbind;
60057 } else {
60058 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
60059 duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, (duk_regconst_t) dest, rc_varname);
60060 x->t = DUK_IVAL_PLAIN;
60061 x->x1.t = DUK_ISPEC_REGCONST;
60062 x->x1.regconst = (duk_regconst_t) dest;
60063 }
60064 return;
60065 }
60066 case DUK_IVAL_NONE:
60067 default: {
60068 DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t));
60069 break;
60070 }
60071 }
60072
60073 DUK_ERROR_INTERNAL_DEFMSG(thr);
60074 return;
60075}
60076
60077/* evaluate to plain value, no forced register (temp/bound reg both ok) */
60078DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60079 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
60080}
60081
60082/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
60083DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60084 duk_reg_t temp;
60085
60086 /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
60087 * restore next temp state.
60088 */
60089 temp = DUK__GETTEMP(comp_ctx);
60090 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
60091 DUK__SETTEMP(comp_ctx, temp);
60092}
60093
60094/* Coerce an duk_ivalue to a register or constant; result register may
60095 * be a temp or a bound register.
60096 *
60097 * The duk_ivalue argument ('x') is converted into a regconst as a
60098 * side effect.
60099 */
60100DUK_LOCAL
60101duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
60102 duk_ivalue *x,
60103 duk_reg_t forced_reg,
60104 duk_small_uint_t flags) {
60105 duk_hthread *thr = comp_ctx->thr;
60106 duk_context *ctx = (duk_context *) thr;
60107 duk_regconst_t reg;
60108 DUK_UNREF(thr);
60109 DUK_UNREF(ctx);
60110
60111 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
60112 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
60113 (long) x->t, (long) x->op,
60114 (long) x->x1.t, (long) x->x1.regconst,
60115 (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
60116 (long) x->x2.t, (long) x->x2.regconst,
60117 (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
60118 (long) forced_reg,
60119 (unsigned long) flags,
60120 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
60121 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
60122 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
60123
60124 /* first coerce to a plain value */
60125 duk__ivalue_toplain_raw(comp_ctx, x, forced_reg);
60126 DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
60127
60128 /* then to a register */
60129 reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
60130 x->x1.t = DUK_ISPEC_REGCONST;
60131 x->x1.regconst = reg;
60132
60133 return reg;
60134}
60135
60136DUK_LOCAL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60137 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
60138}
60139
60140#if 0 /* unused */
60141DUK_LOCAL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60142 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
60143}
60144#endif
60145
60146DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) {
60147 DUK_ASSERT(forced_reg >= 0);
60148 (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
60149}
60150
60151DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60152 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
60153}
60154
60155DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60156 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
60157}
60158
60159/* The issues below can be solved with better flags */
60160
60161/* XXX: many operations actually want toforcedtemp() -- brand new temp? */
60162/* XXX: need a toplain_ignore() which will only coerce a value to a temp
60163 * register if it might have a side effect. Side-effect free values do not
60164 * need to be coerced.
60165 */
60166
60167/*
60168 * Identifier handling
60169 */
60170
60171DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
60172 duk_hthread *thr = comp_ctx->thr;
60173 duk_context *ctx = (duk_context *) thr;
60174 duk_hstring *h_varname;
60175 duk_reg_t ret;
60176
60177 DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
60178 (duk_tval *) duk_get_tval(ctx, -1)));
60179
60180 /*
60181 * Special name handling
60182 */
60183
60184 h_varname = duk_get_hstring(ctx, -1);
60185 DUK_ASSERT(h_varname != NULL);
60186
60187 if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
60188 DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
60189 comp_ctx->curr_func.id_access_arguments = 1;
60190 }
60191
60192 /*
60193 * Inside one or more 'with' statements fall back to slow path always.
60194 * (See e.g. test-stmt-with.js.)
60195 */
60196
60197 if (comp_ctx->curr_func.with_depth > 0) {
60198 DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
60199 goto slow_path;
60200 }
60201
60202 /*
60203 * Any catch bindings ("catch (e)") also affect identifier binding.
60204 *
60205 * Currently, the varmap is modified for the duration of the catch
60206 * clause to ensure any identifier accesses with the catch variable
60207 * name will use slow path.
60208 */
60209
60210 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
60211 if (duk_is_number(ctx, -1)) {
60212 ret = duk_to_int(ctx, -1);
60213 duk_pop(ctx);
60214 } else {
60215 duk_pop(ctx);
60216 goto slow_path;
60217 }
60218
60219 DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
60220 return ret;
60221
60222 slow_path:
60223 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path"));
60224
60225 comp_ctx->curr_func.id_access_slow = 1;
60226 return (duk_reg_t) -1;
60227}
60228
60229/* Lookup an identifier name in the current varmap, indicating whether the
60230 * identifier is register-bound and if not, allocating a constant for the
60231 * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can
60232 * also check (out_reg_varbind >= 0) to check whether or not identifier is
60233 * register bound. The caller must NOT use out_rc_varname at all unless
60234 * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
60235 * is unsigned and doesn't have a "unused" / none value.
60236 */
60237DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
60238 duk_hthread *thr = comp_ctx->thr;
60239 duk_context *ctx = (duk_context *) thr;
60240 duk_reg_t reg_varbind;
60241 duk_regconst_t rc_varname;
60242
60243 /* [ ... varname ] */
60244
60245 duk_dup_top(ctx);
60246 reg_varbind = duk__lookup_active_register_binding(comp_ctx);
60247
60248 if (reg_varbind >= 0) {
60249 *out_reg_varbind = reg_varbind;
60250 *out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
60251 duk_pop(ctx);
60252 return 1;
60253 } else {
60254 rc_varname = duk__getconst(comp_ctx);
60255 *out_reg_varbind = -1;
60256 *out_rc_varname = rc_varname;
60257 return 0;
60258 }
60259}
60260
60261/*
60262 * Label handling
60263 *
60264 * Labels are initially added with flags prohibiting both break and continue.
60265 * When the statement type is finally uncovered (after potentially multiple
60266 * labels), all the labels are updated to allow/prohibit break and continue.
60267 */
60268
60269DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
60270 duk_hthread *thr = comp_ctx->thr;
60271 duk_context *ctx = (duk_context *) thr;
60272 duk_size_t n;
60273 duk_size_t new_size;
60274 duk_uint8_t *p;
60275 duk_labelinfo *li_start, *li;
60276
60277 /* Duplicate (shadowing) labels are not allowed, except for the empty
60278 * labels (which are used as default labels for switch and iteration
60279 * statements).
60280 *
60281 * We could also allow shadowing of non-empty pending labels without any
60282 * other issues than breaking the required label shadowing requirements
60283 * of the E5 specification, see Section 12.12.
60284 */
60285
60286 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
60287 li_start = (duk_labelinfo *) (void *) p;
60288 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60289 n = (duk_size_t) (li - li_start);
60290
60291 while (li > li_start) {
60292 li--;
60293
60294 if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
60295 DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL);
60296 }
60297 }
60298
60299 duk_push_hstring(ctx, h_label);
60300 DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */
60301 (void) duk_put_prop_index(ctx, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
60302
60303 new_size = (n + 1) * sizeof(duk_labelinfo);
60304 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
60305 /* XXX: spare handling, slow now */
60306
60307 /* relookup after possible realloc */
60308 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
60309 li_start = (duk_labelinfo *) (void *) p;
60310 DUK_UNREF(li_start); /* silence scan-build warning */
60311 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60312 li--;
60313
60314 /* Labels can be used for iteration statements but also for other statements,
60315 * in particular a label can be used for a block statement. All cases of a
60316 * named label accept a 'break' so that flag is set here. Iteration statements
60317 * also allow 'continue', so that flag is updated when we figure out the
60318 * statement type.
60319 */
60320
60321 li->flags = DUK_LABEL_FLAG_ALLOW_BREAK;
60322 li->label_id = label_id;
60323 li->h_label = h_label;
60324 li->catch_depth = comp_ctx->curr_func.catch_depth; /* catch depth from current func */
60325 li->pc_label = pc_label;
60326
60327 DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld",
60328 (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label,
60329 (long) li->catch_depth, (long) li->pc_label));
60330}
60331
60332/* Update all labels with matching label_id. */
60333DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) {
60334 duk_uint8_t *p;
60335 duk_labelinfo *li_start, *li;
60336
60337 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos);
60338 li_start = (duk_labelinfo *) (void *) p;
60339 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60340
60341 /* Match labels starting from latest; once label_id no longer matches, we can
60342 * safely exit without checking the rest of the labels (only the topmost labels
60343 * are ever updated).
60344 */
60345 while (li > li_start) {
60346 li--;
60347
60348 if (li->label_id != label_id) {
60349 break;
60350 }
60351
60352 DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld",
60353 (void *) li, (long) label_id, (long) flags));
60354
60355 li->flags = flags;
60356 }
60357}
60358
60359/* Lookup active label information. Break/continue distinction is necessary to handle switch
60360 * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
60361 *
60362 * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
60363 * iteration and switch statements) can. A break will match the closest unlabelled or labelled
60364 * statement. A continue will match the closest unlabelled or labelled iteration statement. It is
60365 * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
60366 * be duplicated, the continue cannot match any valid label outside the switch.
60367 *
60368 * A side effect of these rules is that a LABEL statement related to a switch should never actually
60369 * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the
60370 * continue slot of the switch's LABEL statement.
60371 */
60372
60373/* XXX: awkward, especially the bunch of separate output values -> output struct? */
60374DUK_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) {
60375 duk_hthread *thr = comp_ctx->thr;
60376 duk_context *ctx = (duk_context *) thr;
60377 duk_uint8_t *p;
60378 duk_labelinfo *li_start, *li_end, *li;
60379 duk_bool_t match = 0;
60380
60381 DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
60382 (duk_heaphdr *) h_label, (long) is_break));
60383
60384 DUK_UNREF(ctx);
60385
60386 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
60387 li_start = (duk_labelinfo *) (void *) p;
60388 li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60389 li = li_end;
60390
60391 /* Match labels starting from latest label because there can be duplicate empty
60392 * labels in the label set.
60393 */
60394 while (li > li_start) {
60395 li--;
60396
60397 if (li->h_label != h_label) {
60398 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O",
60399 (long) (li - li_start),
60400 (duk_heaphdr *) li->h_label,
60401 (duk_heaphdr *) h_label));
60402 continue;
60403 }
60404
60405 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)",
60406 (long) (li - li_start), (duk_heaphdr *) h_label));
60407
60408 /* currently all labels accept a break, so no explicit check for it now */
60409 DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
60410
60411 if (is_break) {
60412 /* break matches always */
60413 match = 1;
60414 break;
60415 } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
60416 /* iteration statements allow continue */
60417 match = 1;
60418 break;
60419 } else {
60420 /* continue matched this label -- we can only continue if this is the empty
60421 * label, for which duplication is allowed, and thus there is hope of
60422 * finding a match deeper in the label stack.
60423 */
60424 if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
60425 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
60426 } else {
60427 DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
60428 "allow a continue -> continue lookup deeper in label stack"));
60429 }
60430 }
60431 }
60432 /* XXX: match flag is awkward, rework */
60433 if (!match) {
60434 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
60435 }
60436
60437 DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld",
60438 (duk_heaphdr *) h_label, (long) li->label_id,
60439 (long) li->catch_depth, (long) li->pc_label));
60440
60441 *out_label_id = li->label_id;
60442 *out_label_catch_depth = li->catch_depth;
60443 *out_label_pc = li->pc_label;
60444 *out_is_closest = (li == li_end - 1);
60445}
60446
60447DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len) {
60448 duk_hthread *thr = comp_ctx->thr;
60449 duk_context *ctx = (duk_context *) thr;
60450 duk_size_t new_size;
60451
60452 /* XXX: duk_set_length */
60453 new_size = sizeof(duk_labelinfo) * (duk_size_t) len;
60454 duk_push_int(ctx, len);
60455 duk_put_prop_stridx(ctx, comp_ctx->curr_func.labelnames_idx, DUK_STRIDX_LENGTH);
60456 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
60457}
60458
60459/*
60460 * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
60461 *
60462 * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
60463 * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
60464 * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
60465 */
60466
60467/* object literal key tracking flags */
60468#define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */
60469#define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */
60470#define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */
60471
60472DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60473 duk_hthread *thr = comp_ctx->thr;
60474 duk_reg_t reg_obj; /* result reg */
60475 duk_reg_t reg_temp; /* temp reg */
60476 duk_reg_t temp_start; /* temp reg value for start of loop */
60477 duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */
60478 duk_small_uint_t num_values; /* number of values in current MPUTARR set */
60479 duk_uarridx_t curr_idx; /* current (next) array index */
60480 duk_uarridx_t start_idx; /* start array index of current MPUTARR set */
60481 duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */
60482 duk_bool_t require_comma; /* next loop requires a comma */
60483
60484 /* DUK_TOK_LBRACKET already eaten, current token is right after that */
60485 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
60486
60487 max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
60488
60489 reg_obj = DUK__ALLOCTEMP(comp_ctx);
60490 duk__emit_extraop_b_c(comp_ctx,
60491 DUK_EXTRAOP_NEWARR | DUK__EMIT_FLAG_B_IS_TARGET,
60492 reg_obj,
60493 0); /* XXX: patch initial size afterwards? */
60494 temp_start = DUK__GETTEMP(comp_ctx);
60495
60496 /*
60497 * Emit initializers in sets of maximum max_init_values.
60498 * Corner cases such as single value initializers do not have
60499 * special handling now.
60500 *
60501 * Elided elements must not be emitted as 'undefined' values,
60502 * because such values would be enumerable (which is incorrect).
60503 * Also note that trailing elisions must be reflected in the
60504 * length of the final array but cause no elements to be actually
60505 * inserted.
60506 */
60507
60508 curr_idx = 0;
60509 init_idx = 0; /* tracks maximum initialized index + 1 */
60510 start_idx = 0;
60511 require_comma = 0;
60512
60513 for (;;) {
60514 num_values = 0;
60515 DUK__SETTEMP(comp_ctx, temp_start);
60516
60517 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
60518 break;
60519 }
60520
60521 for (;;) {
60522 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
60523 /* the outer loop will recheck and exit */
60524 break;
60525 }
60526
60527 /* comma check */
60528 if (require_comma) {
60529 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
60530 /* comma after a value, expected */
60531 duk__advance(comp_ctx);
60532 require_comma = 0;
60533 continue;
60534 } else {
60535 goto syntax_error;
60536 }
60537 } else {
60538 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
60539 /* elision - flush */
60540 curr_idx++;
60541 duk__advance(comp_ctx);
60542 /* if num_values > 0, MPUTARR emitted by outer loop after break */
60543 break;
60544 }
60545 }
60546 /* else an array initializer element */
60547
60548 /* initial index */
60549 if (num_values == 0) {
60550 start_idx = curr_idx;
60551 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60552 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx);
60553 }
60554
60555 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
60556 DUK__SETTEMP(comp_ctx, reg_temp);
60557 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
60558 DUK__SETTEMP(comp_ctx, reg_temp + 1);
60559
60560 num_values++;
60561 curr_idx++;
60562 require_comma = 1;
60563
60564 if (num_values >= max_init_values) {
60565 /* MPUTARR emitted by outer loop */
60566 break;
60567 }
60568 }
60569
60570 if (num_values > 0) {
60571 /* - A is a source register (it's not a write target, but used
60572 * to identify the target object) but can be shuffled.
60573 * - B cannot be shuffled normally because it identifies a range
60574 * of registers, the emitter has special handling for this
60575 * (the "no shuffle" flag must not be set).
60576 * - C is a non-register number and cannot be shuffled, but
60577 * never needs to be.
60578 */
60579 duk__emit_a_b_c(comp_ctx,
60580 DUK_OP_MPUTARR |
60581 DUK__EMIT_FLAG_NO_SHUFFLE_C |
60582 DUK__EMIT_FLAG_A_IS_SOURCE,
60583 (duk_regconst_t) reg_obj,
60584 (duk_regconst_t) temp_start,
60585 (duk_regconst_t) num_values);
60586 init_idx = start_idx + num_values;
60587
60588 /* num_values and temp_start reset at top of outer loop */
60589 }
60590 }
60591
60592 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
60593 duk__advance(comp_ctx);
60594
60595 DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
60596 (long) curr_idx, (long) init_idx));
60597
60598 /* trailing elisions? */
60599 if (curr_idx > init_idx) {
60600 /* yes, must set array length explicitly */
60601 DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
60602 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60603 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
60604 duk__emit_extraop_b_c(comp_ctx,
60605 DUK_EXTRAOP_SETALEN,
60606 (duk_regconst_t) reg_obj,
60607 (duk_regconst_t) reg_temp);
60608 }
60609
60610 DUK__SETTEMP(comp_ctx, temp_start);
60611
60612 res->t = DUK_IVAL_PLAIN;
60613 res->x1.t = DUK_ISPEC_REGCONST;
60614 res->x1.regconst = (duk_regconst_t) reg_obj;
60615 return;
60616
60617 syntax_error:
60618 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
60619}
60620
60621/* duplicate/invalid key checks; returns 1 if syntax error */
60622DUK_LOCAL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags) {
60623 duk_hthread *thr = comp_ctx->thr;
60624 duk_context *ctx = (duk_context *) thr;
60625 duk_small_uint_t key_flags;
60626
60627 /* [ ... key_obj key ] */
60628
60629 DUK_ASSERT(duk_is_string(ctx, -1));
60630
60631 /*
60632 * 'key_obj' tracks keys encountered so far by associating an
60633 * integer with flags with already encountered keys. The checks
60634 * below implement E5 Section 11.1.5, step 4 for production:
60635 *
60636 * PropertyNameAndValueList: PropertyNameAndValueList , PropertyAssignment
60637 */
60638
60639 duk_dup(ctx, -1); /* [ ... key_obj key key ] */
60640 duk_get_prop(ctx, -3); /* [ ... key_obj key val ] */
60641 key_flags = duk_to_int(ctx, -1);
60642 duk_pop(ctx); /* [ ... key_obj key ] */
60643
60644 if (new_key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
60645 if ((key_flags & DUK__OBJ_LIT_KEY_PLAIN) && comp_ctx->curr_func.is_strict) {
60646 /* step 4.a */
60647 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key appears twice in strict mode"));
60648 return 1;
60649 }
60650 if (key_flags & (DUK__OBJ_LIT_KEY_GET | DUK__OBJ_LIT_KEY_SET)) {
60651 /* step 4.c */
60652 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key encountered after setter/getter"));
60653 return 1;
60654 }
60655 } else {
60656 if (key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
60657 /* step 4.b */
60658 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered after plain key"));
60659 return 1;
60660 }
60661 if (key_flags & new_key_flags) {
60662 /* step 4.d */
60663 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered twice"));
60664 return 1;
60665 }
60666 }
60667
60668 new_key_flags |= key_flags;
60669 DUK_DDD(DUK_DDDPRINT("setting/updating key %!T flags: 0x%08lx -> 0x%08lx",
60670 (duk_tval *) duk_get_tval(ctx, -1),
60671 (unsigned long) key_flags,
60672 (unsigned long) new_key_flags));
60673 duk_dup(ctx, -1);
60674 duk_push_int(ctx, new_key_flags); /* [ ... key_obj key key flags ] */
60675 duk_put_prop(ctx, -4); /* [ ... key_obj key ] */
60676
60677 return 0;
60678}
60679
60680DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60681 duk_hthread *thr = comp_ctx->thr;
60682 duk_context *ctx = (duk_context *) thr;
60683 duk_reg_t reg_obj; /* result reg */
60684 duk_reg_t reg_key; /* temp reg for key literal */
60685 duk_reg_t reg_temp; /* temp reg */
60686 duk_reg_t temp_start; /* temp reg value for start of loop */
60687 duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */
60688 duk_small_uint_t num_pairs; /* number of pairs in current MPUTOBJ set */
60689 duk_bool_t first; /* first value: comma must not precede the value */
60690 duk_bool_t is_set, is_get; /* temps */
60691
60692 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
60693
60694 max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */
60695
60696 reg_obj = DUK__ALLOCTEMP(comp_ctx);
60697 duk__emit_extraop_b_c(comp_ctx,
60698 DUK_EXTRAOP_NEWOBJ | DUK__EMIT_FLAG_B_IS_TARGET,
60699 reg_obj,
60700 0); /* XXX: patch initial size afterwards? */
60701 temp_start = DUK__GETTEMP(comp_ctx);
60702
60703 /* temp object for tracking / detecting duplicate keys */
60704 duk_push_object(ctx);
60705
60706 /*
60707 * Emit initializers in sets of maximum max_init_pairs keys.
60708 * Setter/getter is handled separately and terminates the
60709 * current set of initializer values. Corner cases such as
60710 * single value initializers do not have special handling now.
60711 */
60712
60713 first = 1;
60714 for (;;) {
60715 num_pairs = 0;
60716 DUK__SETTEMP(comp_ctx, temp_start);
60717
60718 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
60719 break;
60720 }
60721
60722 for (;;) {
60723 /*
60724 * Three possible element formats:
60725 * 1) PropertyName : AssignmentExpression
60726 * 2) get PropertyName () { FunctionBody }
60727 * 3) set PropertyName ( PropertySetParameterList ) { FunctionBody }
60728 *
60729 * PropertyName can be IdentifierName (includes reserved words), a string
60730 * literal, or a number literal. Note that IdentifierName allows 'get' and
60731 * 'set' too, so we need to look ahead to the next token to distinguish:
60732 *
60733 * { get : 1 }
60734 *
60735 * and
60736 *
60737 * { get foo() { return 1 } }
60738 * { get get() { return 1 } } // 'get' as getter propertyname
60739 *
60740 * Finally, a trailing comma is allowed.
60741 *
60742 * Key name is coerced to string at compile time (and ends up as a
60743 * a string constant) even for numeric keys (e.g. "{1:'foo'}").
60744 * These could be emitted using e.g. LDINT, but that seems hardly
60745 * worth the effort and would increase code size.
60746 */
60747
60748 DUK_DDD(DUK_DDDPRINT("object literal inner loop, curr_token->t = %ld",
60749 (long) comp_ctx->curr_token.t));
60750
60751 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
60752 /* the outer loop will recheck and exit */
60753 break;
60754 }
60755 if (num_pairs >= max_init_pairs) {
60756 /* MPUTOBJ emitted by outer loop */
60757 break;
60758 }
60759
60760 if (first) {
60761 first = 0;
60762 } else {
60763 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
60764 goto syntax_error;
60765 }
60766 duk__advance(comp_ctx);
60767 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
60768 /* trailing comma followed by rcurly */
60769 break;
60770 }
60771 }
60772
60773 /* advance to get one step of lookup */
60774 duk__advance(comp_ctx);
60775
60776 /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
60777 * currently treats them always like ordinary identifiers (DUK_TOK_GET
60778 * and DUK_TOK_SET are unused). They need to be detected based on the
60779 * identifier string content.
60780 */
60781
60782 is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
60783 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
60784 is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
60785 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
60786 if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
60787 /* getter/setter */
60788 duk_int_t fnum;
60789
60790 if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
60791 comp_ctx->curr_token.t_nores == DUK_TOK_STRING) {
60792 /* same handling for identifiers and strings */
60793 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
60794 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
60795 } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
60796 duk_push_number(ctx, comp_ctx->curr_token.num);
60797 duk_to_string(ctx, -1);
60798 } else {
60799 goto syntax_error;
60800 }
60801
60802 DUK_ASSERT(duk_is_string(ctx, -1));
60803 if (duk__nud_object_literal_key_check(comp_ctx,
60804 (is_get ? DUK__OBJ_LIT_KEY_GET : DUK__OBJ_LIT_KEY_SET))) {
60805 goto syntax_error;
60806 }
60807 reg_key = duk__getconst(comp_ctx);
60808
60809 if (num_pairs > 0) {
60810 /* - A is a source register (it's not a write target, but used
60811 * to identify the target object) but can be shuffled.
60812 * - B cannot be shuffled normally because it identifies a range
60813 * of registers, the emitter has special handling for this
60814 * (the "no shuffle" flag must not be set).
60815 * - C is a non-register number and cannot be shuffled, but
60816 * never needs to be.
60817 */
60818 duk__emit_a_b_c(comp_ctx,
60819 DUK_OP_MPUTOBJ |
60820 DUK__EMIT_FLAG_NO_SHUFFLE_C |
60821 DUK__EMIT_FLAG_A_IS_SOURCE,
60822 reg_obj,
60823 temp_start,
60824 num_pairs);
60825 num_pairs = 0;
60826 DUK__SETTEMP(comp_ctx, temp_start);
60827 }
60828
60829 /* curr_token = get/set name */
60830 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 1 /*is_setget*/);
60831
60832 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == temp_start);
60833 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60834 duk__emit_a_bc(comp_ctx,
60835 DUK_OP_LDCONST,
60836 (duk_regconst_t) reg_temp,
60837 (duk_regconst_t) reg_key);
60838 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60839 duk__emit_a_bc(comp_ctx,
60840 DUK_OP_CLOSURE,
60841 (duk_regconst_t) reg_temp,
60842 (duk_regconst_t) fnum);
60843
60844 /* Slot C is used in a non-standard fashion (range of regs),
60845 * emitter code has special handling for it (must not set the
60846 * "no shuffle" flag).
60847 */
60848 duk__emit_extraop_b_c(comp_ctx,
60849 (is_get ? DUK_EXTRAOP_INITGET : DUK_EXTRAOP_INITSET),
60850 reg_obj,
60851 temp_start); /* temp_start+0 = key, temp_start+1 = closure */
60852
60853 DUK__SETTEMP(comp_ctx, temp_start);
60854 } else {
60855 /* normal key/value */
60856 if (comp_ctx->prev_token.t_nores == DUK_TOK_IDENTIFIER ||
60857 comp_ctx->prev_token.t_nores == DUK_TOK_STRING) {
60858 /* same handling for identifiers and strings */
60859 DUK_ASSERT(comp_ctx->prev_token.str1 != NULL);
60860 duk_push_hstring(ctx, comp_ctx->prev_token.str1);
60861 } else if (comp_ctx->prev_token.t == DUK_TOK_NUMBER) {
60862 duk_push_number(ctx, comp_ctx->prev_token.num);
60863 duk_to_string(ctx, -1);
60864 } else {
60865 goto syntax_error;
60866 }
60867
60868 DUK_ASSERT(duk_is_string(ctx, -1));
60869 if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
60870 goto syntax_error;
60871 }
60872 reg_key = duk__getconst(comp_ctx);
60873
60874 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60875 duk__emit_a_bc(comp_ctx,
60876 DUK_OP_LDCONST,
60877 (duk_regconst_t) reg_temp,
60878 (duk_regconst_t) reg_key);
60879 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
60880
60881 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
60882 DUK__SETTEMP(comp_ctx, reg_temp);
60883 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
60884 DUK__SETTEMP(comp_ctx, reg_temp + 1);
60885
60886 num_pairs++;
60887 }
60888 }
60889
60890 if (num_pairs > 0) {
60891 /* See MPUTOBJ comments above. */
60892 duk__emit_a_b_c(comp_ctx,
60893 DUK_OP_MPUTOBJ |
60894 DUK__EMIT_FLAG_NO_SHUFFLE_C |
60895 DUK__EMIT_FLAG_A_IS_SOURCE,
60896 reg_obj,
60897 temp_start,
60898 num_pairs);
60899
60900 /* num_pairs and temp_start reset at top of outer loop */
60901 }
60902 }
60903
60904 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
60905 duk__advance(comp_ctx);
60906
60907 DUK__SETTEMP(comp_ctx, temp_start);
60908
60909 res->t = DUK_IVAL_PLAIN;
60910 res->x1.t = DUK_ISPEC_REGCONST;
60911 res->x1.regconst = (duk_regconst_t) reg_obj;
60912
60913 DUK_DDD(DUK_DDDPRINT("final tracking object: %!T",
60914 (duk_tval *) duk_get_tval(ctx, -1)));
60915 duk_pop(ctx);
60916 return;
60917
60918 syntax_error:
60919 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL);
60920}
60921
60922/* Parse argument list. Arguments are written to temps starting from
60923 * "next temp". Returns number of arguments parsed. Expects left paren
60924 * to be already eaten, and eats the right paren before returning.
60925 */
60926DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60927 duk_int_t nargs = 0;
60928 duk_reg_t reg_temp;
60929
60930 /* Note: expect that caller has already eaten the left paren */
60931
60932 DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld",
60933 (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t));
60934
60935 for (;;) {
60936 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
60937 break;
60938 }
60939 if (nargs > 0) {
60940 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
60941 }
60942
60943 /* We want the argument expression value to go to "next temp"
60944 * without additional moves. That should almost always be the
60945 * case, but we double check after expression parsing.
60946 *
60947 * This is not the cleanest possible approach.
60948 */
60949
60950 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */
60951 DUK__SETTEMP(comp_ctx, reg_temp);
60952
60953 /* binding power must be high enough to NOT allow comma expressions directly */
60954 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp); /* always allow 'in', coerce to 'tr' just in case */
60955
60956 DUK__SETTEMP(comp_ctx, reg_temp + 1);
60957 nargs++;
60958
60959 DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp));
60960 }
60961
60962 /* eat the right paren */
60963 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
60964
60965 DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
60966
60967 return nargs;
60968}
60969
60970DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
60971 /* empty expressions can be detected conveniently with nud/led counts */
60972 return (comp_ctx->curr_func.nud_count == 0) &&
60973 (comp_ctx->curr_func.led_count == 0);
60974}
60975
60976DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60977 duk_hthread *thr = comp_ctx->thr;
60978 duk_context *ctx = (duk_context *) thr;
60979 duk_token *tk;
60980 duk_reg_t temp_at_entry;
60981 duk_small_int_t tok;
60982 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
60983
60984 /*
60985 * ctx->prev_token token to process with duk__expr_nud()
60986 * ctx->curr_token updated by caller
60987 *
60988 * Note: the token in the switch below has already been eaten.
60989 */
60990
60991 temp_at_entry = DUK__GETTEMP(comp_ctx);
60992
60993 comp_ctx->curr_func.nud_count++;
60994
60995 tk = &comp_ctx->prev_token;
60996 tok = tk->t;
60997 res->t = DUK_IVAL_NONE;
60998
60999 DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
61000 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
61001
61002 switch (tok) {
61003
61004 /* PRIMARY EXPRESSIONS */
61005
61006 case DUK_TOK_THIS: {
61007 duk_reg_t reg_temp;
61008 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61009 duk__emit_extraop_bc(comp_ctx,
61010 DUK_EXTRAOP_LDTHIS,
61011 (duk_regconst_t) reg_temp);
61012 res->t = DUK_IVAL_PLAIN;
61013 res->x1.t = DUK_ISPEC_REGCONST;
61014 res->x1.regconst = (duk_regconst_t) reg_temp;
61015 return;
61016 }
61017 case DUK_TOK_IDENTIFIER: {
61018 res->t = DUK_IVAL_VAR;
61019 res->x1.t = DUK_ISPEC_VALUE;
61020 duk_push_hstring(ctx, tk->str1);
61021 duk_replace(ctx, res->x1.valstack_idx);
61022 return;
61023 }
61024 case DUK_TOK_NULL: {
61025 duk_push_null(ctx);
61026 goto plain_value;
61027 }
61028 case DUK_TOK_TRUE: {
61029 duk_push_true(ctx);
61030 goto plain_value;
61031 }
61032 case DUK_TOK_FALSE: {
61033 duk_push_false(ctx);
61034 goto plain_value;
61035 }
61036 case DUK_TOK_NUMBER: {
61037 duk_push_number(ctx, tk->num);
61038 goto plain_value;
61039 }
61040 case DUK_TOK_STRING: {
61041 DUK_ASSERT(tk->str1 != NULL);
61042 duk_push_hstring(ctx, tk->str1);
61043 goto plain_value;
61044 }
61045 case DUK_TOK_REGEXP: {
61046#ifdef DUK_USE_REGEXP_SUPPORT
61047 duk_reg_t reg_temp;
61048 duk_regconst_t rc_re_bytecode; /* const */
61049 duk_regconst_t rc_re_source; /* const */
61050
61051 DUK_ASSERT(tk->str1 != NULL);
61052 DUK_ASSERT(tk->str2 != NULL);
61053
61054 DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
61055 (duk_heaphdr *) tk->str1,
61056 (duk_heaphdr *) tk->str2));
61057
61058 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61059 duk_push_hstring(ctx, tk->str1);
61060 duk_push_hstring(ctx, tk->str2);
61061
61062 /* [ ... pattern flags ] */
61063
61064 duk_regexp_compile(thr);
61065
61066 /* [ ... escaped_source bytecode ] */
61067
61068 rc_re_bytecode = duk__getconst(comp_ctx);
61069 rc_re_source = duk__getconst(comp_ctx);
61070
61071 duk__emit_a_b_c(comp_ctx,
61072 DUK_OP_REGEXP,
61073 (duk_regconst_t) reg_temp /*a*/,
61074 rc_re_bytecode /*b*/,
61075 rc_re_source /*c*/);
61076
61077 res->t = DUK_IVAL_PLAIN;
61078 res->x1.t = DUK_ISPEC_REGCONST;
61079 res->x1.regconst = (duk_regconst_t) reg_temp;
61080 return;
61081#else /* DUK_USE_REGEXP_SUPPORT */
61082 goto syntax_error;
61083#endif /* DUK_USE_REGEXP_SUPPORT */
61084 }
61085 case DUK_TOK_LBRACKET: {
61086 DUK_DDD(DUK_DDDPRINT("parsing array literal"));
61087 duk__nud_array_literal(comp_ctx, res);
61088 return;
61089 }
61090 case DUK_TOK_LCURLY: {
61091 DUK_DDD(DUK_DDDPRINT("parsing object literal"));
61092 duk__nud_object_literal(comp_ctx, res);
61093 return;
61094 }
61095 case DUK_TOK_LPAREN: {
61096 duk_bool_t prev_allow_in;
61097
61098 comp_ctx->curr_func.paren_level++;
61099 prev_allow_in = comp_ctx->curr_func.allow_in;
61100 comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */
61101
61102 duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */
61103
61104 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
61105 comp_ctx->curr_func.allow_in = prev_allow_in;
61106 comp_ctx->curr_func.paren_level--;
61107 return;
61108 }
61109
61110 /* MEMBER/NEW/CALL EXPRESSIONS */
61111
61112 case DUK_TOK_NEW: {
61113 /*
61114 * Parsing an expression starting with 'new' is tricky because
61115 * there are multiple possible productions deriving from
61116 * LeftHandSideExpression which begin with 'new'.
61117 *
61118 * We currently resort to one-token lookahead to distinguish the
61119 * cases. Hopefully this is correct. The binding power must be
61120 * such that parsing ends at an LPAREN (CallExpression) but not at
61121 * a PERIOD or LBRACKET (MemberExpression).
61122 *
61123 * See doc/compiler.rst for discussion on the parsing approach,
61124 * and testcases/test-dev-new.js for a bunch of documented tests.
61125 */
61126
61127 duk_reg_t reg_target;
61128 duk_int_t nargs;
61129
61130 DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
61131
61132 reg_target = DUK__ALLOCTEMP(comp_ctx);
61133 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
61134 DUK__SETTEMP(comp_ctx, reg_target + 1);
61135
61136 if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
61137 /* 'new' MemberExpression Arguments */
61138 DUK_DDD(DUK_DDDPRINT("new expression has argument list"));
61139 duk__advance(comp_ctx);
61140 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp", reg_target + 1 */
61141 /* right paren eaten */
61142 } else {
61143 /* 'new' MemberExpression */
61144 DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
61145 nargs = 0;
61146 }
61147
61148 /* Opcode slot C is used in a non-standard way, so shuffling
61149 * is not allowed.
61150 */
61151 duk__emit_a_b_c(comp_ctx,
61152 DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
61153 0 /*unused*/,
61154 reg_target /*target*/,
61155 nargs /*num_args*/);
61156
61157 DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
61158
61159 res->t = DUK_IVAL_PLAIN;
61160 res->x1.t = DUK_ISPEC_REGCONST;
61161 res->x1.regconst = (duk_regconst_t) reg_target;
61162 return;
61163 }
61164
61165 /* FUNCTION EXPRESSIONS */
61166
61167 case DUK_TOK_FUNCTION: {
61168 /* Function expression. Note that any statement beginning with 'function'
61169 * is handled by the statement parser as a function declaration, or a
61170 * non-standard function expression/statement (or a SyntaxError). We only
61171 * handle actual function expressions (occurring inside an expression) here.
61172 *
61173 * O(depth^2) parse count for inner functions is handled by recording a
61174 * lexer offset on the first compilation pass, so that the function can
61175 * be efficiently skipped on the second pass. This is encapsulated into
61176 * duk__parse_func_like_fnum().
61177 */
61178
61179 duk_reg_t reg_temp;
61180 duk_int_t fnum;
61181
61182 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61183
61184 /* curr_token follows 'function' */
61185 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 0 /*is_setget*/);
61186 DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum));
61187
61188 duk__emit_a_bc(comp_ctx,
61189 DUK_OP_CLOSURE,
61190 (duk_regconst_t) reg_temp /*a*/,
61191 (duk_regconst_t) fnum /*bc*/);
61192
61193 res->t = DUK_IVAL_PLAIN;
61194 res->x1.t = DUK_ISPEC_REGCONST;
61195 res->x1.regconst = (duk_regconst_t) reg_temp;
61196 return;
61197 }
61198
61199 /* UNARY EXPRESSIONS */
61200
61201 case DUK_TOK_DELETE: {
61202 /* Delete semantics are a bit tricky. The description in E5 specification
61203 * is kind of confusing, because it distinguishes between resolvability of
61204 * a reference (which is only known at runtime) seemingly at compile time
61205 * (= SyntaxError throwing).
61206 */
61207 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61208 if (res->t == DUK_IVAL_VAR) {
61209 /* not allowed in strict mode, regardless of whether resolves;
61210 * in non-strict mode DELVAR handles both non-resolving and
61211 * resolving cases (the specification description is a bit confusing).
61212 */
61213
61214 duk_reg_t reg_temp;
61215 duk_reg_t reg_varbind;
61216 duk_regconst_t rc_varname;
61217
61218 if (comp_ctx->curr_func.is_strict) {
61219 DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER);
61220 }
61221
61222 DUK__SETTEMP(comp_ctx, temp_at_entry);
61223 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61224
61225 duk_dup(ctx, res->x1.valstack_idx);
61226 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61227 /* register bound variables are non-configurable -> always false */
61228 duk__emit_extraop_bc(comp_ctx,
61229 DUK_EXTRAOP_LDFALSE,
61230 (duk_regconst_t) reg_temp);
61231 } else {
61232 duk_dup(ctx, res->x1.valstack_idx);
61233 rc_varname = duk__getconst(comp_ctx);
61234 duk__emit_a_b(comp_ctx,
61235 DUK_OP_DELVAR,
61236 (duk_regconst_t) reg_temp,
61237 (duk_regconst_t) rc_varname);
61238 }
61239 res->t = DUK_IVAL_PLAIN;
61240 res->x1.t = DUK_ISPEC_REGCONST;
61241 res->x1.regconst = (duk_regconst_t) reg_temp;
61242 } else if (res->t == DUK_IVAL_PROP) {
61243 duk_reg_t reg_temp;
61244 duk_reg_t reg_obj;
61245 duk_regconst_t rc_key;
61246
61247 DUK__SETTEMP(comp_ctx, temp_at_entry);
61248 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61249 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
61250 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
61251 duk__emit_a_b_c(comp_ctx,
61252 DUK_OP_DELPROP,
61253 (duk_regconst_t) reg_temp,
61254 (duk_regconst_t) reg_obj,
61255 rc_key);
61256
61257 res->t = DUK_IVAL_PLAIN;
61258 res->x1.t = DUK_ISPEC_REGCONST;
61259 res->x1.regconst = (duk_regconst_t) reg_temp;
61260 } else {
61261 /* non-Reference deletion is always 'true', even in strict mode */
61262 duk_push_true(ctx);
61263 goto plain_value;
61264 }
61265 return;
61266 }
61267 case DUK_TOK_VOID: {
61268 duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61269 duk_push_undefined(ctx);
61270 goto plain_value;
61271 }
61272 case DUK_TOK_TYPEOF: {
61273 /* 'typeof' must handle unresolvable references without throwing
61274 * a ReferenceError (E5 Section 11.4.3). Register mapped values
61275 * will never be unresolvable so special handling is only required
61276 * when an identifier is a "slow path" one.
61277 */
61278 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61279
61280 if (res->t == DUK_IVAL_VAR) {
61281 duk_reg_t reg_varbind;
61282 duk_regconst_t rc_varname;
61283 duk_reg_t reg_temp;
61284
61285 duk_dup(ctx, res->x1.valstack_idx);
61286 if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61287 DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
61288 "at compile time, need to use special run-time handling"));
61289 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61290 duk__emit_extraop_b_c(comp_ctx,
61291 DUK_EXTRAOP_TYPEOFID | DUK__EMIT_FLAG_B_IS_TARGET,
61292 reg_temp,
61293 rc_varname);
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
61301 args = (DUK_EXTRAOP_TYPEOF << 8) + 0;
61302 goto unary_extraop;
61303 }
61304 case DUK_TOK_INCREMENT: {
61305 args = (DUK_OP_PREINCR << 8) + 0;
61306 goto preincdec;
61307 }
61308 case DUK_TOK_DECREMENT: {
61309 args = (DUK_OP_PREDECR << 8) + 0;
61310 goto preincdec;
61311 }
61312 case DUK_TOK_ADD: {
61313 /* unary plus */
61314 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61315 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
61316 duk_is_number(ctx, res->x1.valstack_idx)) {
61317 /* unary plus of a number is identity */
61318 ;
61319 return;
61320 }
61321 args = (DUK_EXTRAOP_UNP << 8) + 0;
61322 goto unary_extraop;
61323 }
61324 case DUK_TOK_SUB: {
61325 /* unary minus */
61326 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61327 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
61328 duk_is_number(ctx, res->x1.valstack_idx)) {
61329 /* this optimization is important to handle negative literals
61330 * (which are not directly provided by the lexical grammar)
61331 */
61332 duk_tval *tv_num;
61333 duk_double_union du;
61334
61335 tv_num = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
61336 DUK_ASSERT(tv_num != NULL);
61337 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
61338 du.d = DUK_TVAL_GET_NUMBER(tv_num);
61339 du.d = -du.d;
61340 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
61341 DUK_TVAL_SET_NUMBER(tv_num, du.d);
61342 return;
61343 }
61344 args = (DUK_EXTRAOP_UNM << 8) + 0;
61345 goto unary_extraop;
61346 }
61347 case DUK_TOK_BNOT: {
61348 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61349 args = (DUK_EXTRAOP_BNOT << 8) + 0;
61350 goto unary_extraop;
61351 }
61352 case DUK_TOK_LNOT: {
61353 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61354 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) {
61355 /* Very minimal inlining to handle common idioms '!0' and '!1',
61356 * and also boolean arguments like '!false' and '!true'.
61357 */
61358 duk_tval *tv_val;
61359
61360 tv_val = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
61361 DUK_ASSERT(tv_val != NULL);
61362 if (DUK_TVAL_IS_NUMBER(tv_val)) {
61363 duk_double_t d;
61364 d = DUK_TVAL_GET_NUMBER(tv_val);
61365 if (d == 0.0) {
61366 /* Matches both +0 and -0 on purpose. */
61367 DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true"));
61368 DUK_TVAL_SET_BOOLEAN_TRUE(tv_val);
61369 return;
61370 } else if (d == 1.0) {
61371 DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
61372 DUK_TVAL_SET_BOOLEAN_FALSE(tv_val);
61373 return;
61374 }
61375 } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
61376 duk_small_int_t v;
61377 v = DUK_TVAL_GET_BOOLEAN(tv_val);
61378 DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
61379 DUK_ASSERT(v == 0 || v == 1);
61380 DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01);
61381 return;
61382 }
61383 }
61384 args = (DUK_EXTRAOP_LNOT << 8) + 0;
61385 goto unary_extraop;
61386 }
61387
61388 } /* end switch */
61389
61390 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
61391 return;
61392
61393 unary_extraop:
61394 {
61395 /* Note: must coerce to a (writable) temp register, so that e.g. "!x" where x
61396 * is a reg-mapped variable works correctly (does not mutate the variable register).
61397 */
61398
61399 duk_reg_t reg_temp;
61400 reg_temp = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
61401 duk__emit_extraop_bc(comp_ctx,
61402 (args >> 8),
61403 (duk_regconst_t) reg_temp);
61404 res->t = DUK_IVAL_PLAIN;
61405 res->x1.t = DUK_ISPEC_REGCONST;
61406 res->x1.regconst = (duk_regconst_t) reg_temp;
61407 return;
61408 }
61409
61410 preincdec:
61411 {
61412 /* preincrement and predecrement */
61413 duk_reg_t reg_res;
61414 duk_small_uint_t args_op = args >> 8;
61415
61416 /* Specific assumptions for opcode numbering. */
61417 DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV);
61418 DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV);
61419 DUK_ASSERT(DUK_OP_PREINCR + 8 == DUK_OP_PREINCP);
61420 DUK_ASSERT(DUK_OP_PREDECR + 8 == DUK_OP_PREDECP);
61421
61422 reg_res = DUK__ALLOCTEMP(comp_ctx);
61423
61424 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61425 if (res->t == DUK_IVAL_VAR) {
61426 duk_hstring *h_varname;
61427 duk_reg_t reg_varbind;
61428 duk_regconst_t rc_varname;
61429
61430 h_varname = duk_get_hstring(ctx, res->x1.valstack_idx);
61431 DUK_ASSERT(h_varname != NULL);
61432
61433 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
61434 goto syntax_error;
61435 }
61436
61437 duk_dup(ctx, res->x1.valstack_idx);
61438 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61439 duk__emit_a_bc(comp_ctx,
61440 args_op, /* e.g. DUK_OP_PREINCR */
61441 (duk_regconst_t) reg_res,
61442 (duk_regconst_t) reg_varbind);
61443 } else {
61444 duk__emit_a_bc(comp_ctx,
61445 args_op + 4, /* e.g. DUK_OP_PREINCV */
61446 (duk_regconst_t) reg_res,
61447 rc_varname);
61448 }
61449
61450 DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
61451 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
61452 } else if (res->t == DUK_IVAL_PROP) {
61453 duk_reg_t reg_obj; /* allocate to reg only (not const) */
61454 duk_regconst_t rc_key;
61455 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
61456 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
61457 duk__emit_a_b_c(comp_ctx,
61458 args_op + 8, /* e.g. DUK_OP_PREINCP */
61459 (duk_regconst_t) reg_res,
61460 (duk_regconst_t) reg_obj,
61461 rc_key);
61462 } else {
61463 /* Technically return value is not needed because INVLHS will
61464 * unconditially throw a ReferenceError. Coercion is necessary
61465 * for proper semantics (consider ToNumber() called for an object).
61466 * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
61467 */
61468
61469 duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
61470 duk__emit_extraop_bc(comp_ctx,
61471 DUK_EXTRAOP_UNP,
61472 reg_res); /* for side effects, result ignored */
61473 duk__emit_extraop_only(comp_ctx,
61474 DUK_EXTRAOP_INVLHS);
61475 }
61476 res->t = DUK_IVAL_PLAIN;
61477 res->x1.t = DUK_ISPEC_REGCONST;
61478 res->x1.regconst = (duk_regconst_t) reg_res;
61479 DUK__SETTEMP(comp_ctx, reg_res + 1);
61480 return;
61481 }
61482
61483 plain_value:
61484 {
61485 /* Stack top contains plain value */
61486 res->t = DUK_IVAL_PLAIN;
61487 res->x1.t = DUK_ISPEC_VALUE;
61488 duk_replace(ctx, res->x1.valstack_idx);
61489 return;
61490 }
61491
61492 syntax_error:
61493 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
61494}
61495
61496/* XXX: add flag to indicate whether caller cares about return value; this
61497 * affects e.g. handling of assignment expressions. This change needs API
61498 * changes elsewhere too.
61499 */
61500DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
61501 duk_hthread *thr = comp_ctx->thr;
61502 duk_context *ctx = (duk_context *) thr;
61503 duk_token *tk;
61504 duk_small_int_t tok;
61505 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
61506
61507 /*
61508 * ctx->prev_token token to process with duk__expr_led()
61509 * ctx->curr_token updated by caller
61510 */
61511
61512 comp_ctx->curr_func.led_count++;
61513
61514 /* The token in the switch has already been eaten here */
61515 tk = &comp_ctx->prev_token;
61516 tok = tk->t;
61517
61518 DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
61519 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
61520
61521 /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
61522
61523 switch (tok) {
61524
61525 /* PRIMARY EXPRESSIONS */
61526
61527 case DUK_TOK_PERIOD: {
61528 /* Property access expressions are critical for correct LHS ordering,
61529 * see comments in duk__expr()!
61530 *
61531 * A conservative approach would be to use duk__ivalue_totempconst()
61532 * for 'left'. However, allowing a reg-bound variable seems safe here
61533 * and is nice because "foo.bar" is a common expression. If the ivalue
61534 * is used in an expression a GETPROP will occur before any changes to
61535 * the base value can occur. If the ivalue is used as an assignment
61536 * LHS, the assignment code will ensure the base value is safe from
61537 * RHS mutation.
61538 */
61539
61540 /* XXX: This now coerces an identifier into a GETVAR to a temp, which
61541 * causes an extra LDREG in call setup. It's sufficient to coerce to a
61542 * unary ivalue?
61543 */
61544 duk__ivalue_toplain(comp_ctx, left);
61545
61546 /* NB: must accept reserved words as property name */
61547 if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) {
61548 DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
61549 }
61550
61551 res->t = DUK_IVAL_PROP;
61552 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
61553 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
61554 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
61555 duk_replace(ctx, res->x2.valstack_idx);
61556 res->x2.t = DUK_ISPEC_VALUE;
61557
61558 /* special RegExp literal handling after IdentifierName */
61559 comp_ctx->curr_func.reject_regexp_in_adv = 1;
61560
61561 duk__advance(comp_ctx);
61562 return;
61563 }
61564 case DUK_TOK_LBRACKET: {
61565 /* Property access expressions are critical for correct LHS ordering,
61566 * see comments in duk__expr()!
61567 */
61568
61569 /* XXX: optimize temp reg use */
61570 /* XXX: similar coercion issue as in DUK_TOK_PERIOD */
61571 /* XXX: coerce to regs? it might be better for enumeration use, where the
61572 * same PROP ivalue is used multiple times. Or perhaps coerce PROP further
61573 * there?
61574 */
61575 /* XXX: for simple cases like x['y'] an unnecessary LDREG is
61576 * emitted for the base value; could avoid it if we knew that
61577 * the key expression is safe (e.g. just a single literal).
61578 */
61579
61580 /* The 'left' value must not be a register bound variable
61581 * because it may be mutated during the rest of the expression
61582 * and E5.1 Section 11.2.1 specifies the order of evaluation
61583 * so that the base value is evaluated first.
61584 * See: test-bug-nested-prop-mutate.js.
61585 */
61586 duk__ivalue_totempconst(comp_ctx, left);
61587 duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */
61588 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
61589
61590 res->t = DUK_IVAL_PROP;
61591 duk__copy_ispec(comp_ctx, &res->x1, &res->x2); /* res.x1 -> res.x2 */
61592 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
61593 return;
61594 }
61595 case DUK_TOK_LPAREN: {
61596 /* function call */
61597 duk_reg_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
61598 duk_int_t nargs;
61599 duk_small_uint_t call_flags = 0;
61600
61601 /*
61602 * XXX: attempt to get the call result to "next temp" whenever
61603 * possible to avoid unnecessary register shuffles.
61604 *
61605 * XXX: CSPROP (and CSREG) can overwrite the call target register, and save one temp,
61606 * if the call target is a temporary register and at the top of the temp reg "stack".
61607 */
61608
61609 /*
61610 * Setup call: target and 'this' binding. Three cases:
61611 *
61612 * 1. Identifier base (e.g. "foo()")
61613 * 2. Property base (e.g. "foo.bar()")
61614 * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
61615 */
61616
61617 if (left->t == DUK_IVAL_VAR) {
61618 duk_hstring *h_varname;
61619 duk_reg_t reg_varbind;
61620 duk_regconst_t rc_varname;
61621
61622 DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
61623
61624 h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
61625 DUK_ASSERT(h_varname != NULL);
61626 if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
61627 /* Potential direct eval call detected, flag the CALL
61628 * so that a run-time "direct eval" check is made and
61629 * special behavior may be triggered. Note that this
61630 * does not prevent 'eval' from being register bound.
61631 */
61632 DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
61633 "-> enabling EVALCALL flag, marking function "
61634 "as may_direct_eval"));
61635 call_flags |= DUK_BC_CALL_FLAG_EVALCALL;
61636
61637 comp_ctx->curr_func.may_direct_eval = 1;
61638 }
61639
61640 duk_dup(ctx, left->x1.valstack_idx);
61641 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61642 duk__emit_a_b(comp_ctx,
61643 DUK_OP_CSREG,
61644 (duk_regconst_t) (reg_cs + 0),
61645 (duk_regconst_t) reg_varbind);
61646 } else {
61647 duk__emit_a_b(comp_ctx,
61648 DUK_OP_CSVAR,
61649 (duk_regconst_t) (reg_cs + 0),
61650 rc_varname);
61651 }
61652 } else if (left->t == DUK_IVAL_PROP) {
61653 DUK_DDD(DUK_DDDPRINT("function call with property base"));
61654
61655 duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 0); /* base */
61656 duk__ispec_toforcedreg(comp_ctx, &left->x2, reg_cs + 1); /* key */
61657 duk__emit_a_b_c(comp_ctx,
61658 DUK_OP_CSPROP,
61659 (duk_regconst_t) (reg_cs + 0),
61660 (duk_regconst_t) (reg_cs + 0),
61661 (duk_regconst_t) (reg_cs + 1)); /* in-place setup */
61662 } else {
61663 DUK_DDD(DUK_DDDPRINT("function call with register base"));
61664
61665 duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
61666 duk__emit_a_b(comp_ctx,
61667 DUK_OP_CSREG,
61668 (duk_regconst_t) (reg_cs + 0),
61669 (duk_regconst_t) (reg_cs + 0)); /* in-place setup */
61670 }
61671
61672 DUK__SETTEMP(comp_ctx, reg_cs + 2);
61673 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
61674
61675 /* Tailcalls are handled by back-patching the TAILCALL flag to the
61676 * already emitted instruction later (in return statement parser).
61677 * Since A and C have a special meaning here, they cannot be "shuffled".
61678 */
61679
61680 duk__emit_a_b_c(comp_ctx,
61681 DUK_OP_CALL | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
61682 (duk_regconst_t) call_flags /*flags*/,
61683 (duk_regconst_t) reg_cs /*basereg*/,
61684 (duk_regconst_t) nargs /*numargs*/);
61685 DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */
61686
61687 res->t = DUK_IVAL_PLAIN;
61688 res->x1.t = DUK_ISPEC_REGCONST;
61689 res->x1.regconst = (duk_regconst_t) reg_cs;
61690 return;
61691 }
61692
61693 /* POSTFIX EXPRESSION */
61694
61695 case DUK_TOK_INCREMENT: {
61696 args = (DUK_OP_POSTINCR << 8) + 0;
61697 goto postincdec;
61698 }
61699 case DUK_TOK_DECREMENT: {
61700 args = (DUK_OP_POSTDECR << 8) + 0;
61701 goto postincdec;
61702 }
61703
61704 /* MULTIPLICATIVE EXPRESSION */
61705
61706 case DUK_TOK_MUL: {
61707 args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
61708 goto binary;
61709 }
61710 case DUK_TOK_DIV: {
61711 args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
61712 goto binary;
61713 }
61714 case DUK_TOK_MOD: {
61715 args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
61716 goto binary;
61717 }
61718
61719 /* ADDITIVE EXPRESSION */
61720
61721 case DUK_TOK_ADD: {
61722 args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
61723 goto binary;
61724 }
61725 case DUK_TOK_SUB: {
61726 args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
61727 goto binary;
61728 }
61729
61730 /* SHIFT EXPRESSION */
61731
61732 case DUK_TOK_ALSHIFT: {
61733 /* << */
61734 args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
61735 goto binary;
61736 }
61737 case DUK_TOK_ARSHIFT: {
61738 /* >> */
61739 args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
61740 goto binary;
61741 }
61742 case DUK_TOK_RSHIFT: {
61743 /* >>> */
61744 args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
61745 goto binary;
61746 }
61747
61748 /* RELATIONAL EXPRESSION */
61749
61750 case DUK_TOK_LT: {
61751 /* < */
61752 args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
61753 goto binary;
61754 }
61755 case DUK_TOK_GT: {
61756 args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
61757 goto binary;
61758 }
61759 case DUK_TOK_LE: {
61760 args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
61761 goto binary;
61762 }
61763 case DUK_TOK_GE: {
61764 args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
61765 goto binary;
61766 }
61767 case DUK_TOK_INSTANCEOF: {
61768 args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_INSTOF << 8) + DUK__BP_RELATIONAL;
61769 goto binary;
61770 }
61771 case DUK_TOK_IN: {
61772 args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_IN << 8) + DUK__BP_RELATIONAL;
61773 goto binary;
61774 }
61775
61776 /* EQUALITY EXPRESSION */
61777
61778 case DUK_TOK_EQ: {
61779 args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
61780 goto binary;
61781 }
61782 case DUK_TOK_NEQ: {
61783 args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
61784 goto binary;
61785 }
61786 case DUK_TOK_SEQ: {
61787 args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
61788 goto binary;
61789 }
61790 case DUK_TOK_SNEQ: {
61791 args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
61792 goto binary;
61793 }
61794
61795 /* BITWISE EXPRESSIONS */
61796
61797 case DUK_TOK_BAND: {
61798 args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
61799 goto binary;
61800 }
61801 case DUK_TOK_BXOR: {
61802 args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
61803 goto binary;
61804 }
61805 case DUK_TOK_BOR: {
61806 args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
61807 goto binary;
61808 }
61809
61810 /* LOGICAL EXPRESSIONS */
61811
61812 case DUK_TOK_LAND: {
61813 /* syntactically left-associative but parsed as right-associative */
61814 args = (1 << 8) + DUK__BP_LAND - 1;
61815 goto binary_logical;
61816 }
61817 case DUK_TOK_LOR: {
61818 /* syntactically left-associative but parsed as right-associative */
61819 args = (0 << 8) + DUK__BP_LOR - 1;
61820 goto binary_logical;
61821 }
61822
61823 /* CONDITIONAL EXPRESSION */
61824
61825 case DUK_TOK_QUESTION: {
61826 /* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
61827 * but only if it really is a temp. Nothing fancy here now.
61828 */
61829 duk_reg_t reg_temp;
61830 duk_int_t pc_jump1;
61831 duk_int_t pc_jump2;
61832
61833 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61834 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
61835 duk__emit_if_true_skip(comp_ctx, reg_temp);
61836 pc_jump1 = duk__emit_jump_empty(comp_ctx); /* jump to false */
61837 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
61838 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
61839 pc_jump2 = duk__emit_jump_empty(comp_ctx); /* jump to end */
61840 duk__patch_jump_here(comp_ctx, pc_jump1);
61841 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
61842 duk__patch_jump_here(comp_ctx, pc_jump2);
61843
61844 DUK__SETTEMP(comp_ctx, reg_temp + 1);
61845 res->t = DUK_IVAL_PLAIN;
61846 res->x1.t = DUK_ISPEC_REGCONST;
61847 res->x1.regconst = (duk_regconst_t) reg_temp;
61848 return;
61849 }
61850
61851 /* ASSIGNMENT EXPRESSION */
61852
61853 case DUK_TOK_EQUALSIGN: {
61854 /*
61855 * Assignments are right associative, allows e.g.
61856 * a = 5;
61857 * a += b = 9; // same as a += (b = 9)
61858 * -> expression value 14, a = 14, b = 9
61859 *
61860 * Right associativiness is reflected in the BP for recursion,
61861 * "-1" ensures assignment operations are allowed.
61862 *
61863 * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
61864 */
61865 args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */
61866 goto assign;
61867 }
61868 case DUK_TOK_ADD_EQ: {
61869 /* right associative */
61870 args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
61871 goto assign;
61872 }
61873 case DUK_TOK_SUB_EQ: {
61874 /* right associative */
61875 args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
61876 goto assign;
61877 }
61878 case DUK_TOK_MUL_EQ: {
61879 /* right associative */
61880 args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
61881 goto assign;
61882 }
61883 case DUK_TOK_DIV_EQ: {
61884 /* right associative */
61885 args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
61886 goto assign;
61887 }
61888 case DUK_TOK_MOD_EQ: {
61889 /* right associative */
61890 args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
61891 goto assign;
61892 }
61893 case DUK_TOK_ALSHIFT_EQ: {
61894 /* right associative */
61895 args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
61896 goto assign;
61897 }
61898 case DUK_TOK_ARSHIFT_EQ: {
61899 /* right associative */
61900 args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
61901 goto assign;
61902 }
61903 case DUK_TOK_RSHIFT_EQ: {
61904 /* right associative */
61905 args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
61906 goto assign;
61907 }
61908 case DUK_TOK_BAND_EQ: {
61909 /* right associative */
61910 args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
61911 goto assign;
61912 }
61913 case DUK_TOK_BOR_EQ: {
61914 /* right associative */
61915 args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
61916 goto assign;
61917 }
61918 case DUK_TOK_BXOR_EQ: {
61919 /* right associative */
61920 args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
61921 goto assign;
61922 }
61923
61924 /* COMMA */
61925
61926 case DUK_TOK_COMMA: {
61927 /* right associative */
61928
61929 duk__ivalue_toplain_ignore(comp_ctx, left); /* need side effects, not value */
61930 duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/);
61931
61932 /* return 'res' (of right part) as our result */
61933 return;
61934 }
61935
61936 default: {
61937 break;
61938 }
61939 }
61940
61941 DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok));
61942 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
61943 return;
61944
61945#if 0
61946 /* XXX: shared handling for 'duk__expr_lhs'? */
61947 if (comp_ctx->curr_func.paren_level == 0 && XXX) {
61948 comp_ctx->curr_func.duk__expr_lhs = 0;
61949 }
61950#endif
61951
61952 binary:
61953 /*
61954 * Shared handling of binary operations
61955 *
61956 * args = (is_extraop << 16) + (opcode << 8) + rbp
61957 */
61958 {
61959 duk__ivalue_toplain(comp_ctx, left);
61960 duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
61961
61962 /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
61963 DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
61964 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
61965
61966 res->t = (args >> 16) ? DUK_IVAL_ARITH_EXTRAOP : DUK_IVAL_ARITH;
61967 res->op = (args >> 8) & 0xff;
61968
61969 res->x2.t = res->x1.t;
61970 res->x2.regconst = res->x1.regconst;
61971 duk_copy(ctx, res->x1.valstack_idx, res->x2.valstack_idx);
61972
61973 res->x1.t = left->x1.t;
61974 res->x1.regconst = left->x1.regconst;
61975 duk_copy(ctx, left->x1.valstack_idx, res->x1.valstack_idx);
61976
61977 DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
61978 (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
61979 return;
61980 }
61981
61982 binary_logical:
61983 /*
61984 * Shared handling for logical AND and logical OR.
61985 *
61986 * args = (truthval << 8) + rbp
61987 *
61988 * Truthval determines when to skip right-hand-side.
61989 * For logical AND truthval=1, for logical OR truthval=0.
61990 *
61991 * See doc/compiler.rst for discussion on compiling logical
61992 * AND and OR expressions. The approach here is very simplistic,
61993 * generating extra jumps and multiple evaluations of truth values,
61994 * but generates code on-the-fly with only local back-patching.
61995 *
61996 * Both logical AND and OR are syntactically left-associated.
61997 * However, logical ANDs are compiled as right associative
61998 * expressions, i.e. "A && B && C" as "A && (B && C)", to allow
61999 * skip jumps to skip over the entire tail. Similarly for logical OR.
62000 */
62001
62002 {
62003 duk_reg_t reg_temp;
62004 duk_int_t pc_jump;
62005 duk_small_uint_t args_truthval = args >> 8;
62006 duk_small_uint_t args_rbp = args & 0xff;
62007
62008 /* XXX: unoptimal use of temps, resetting */
62009
62010 reg_temp = DUK__ALLOCTEMP(comp_ctx);
62011
62012 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
62013 duk__emit_a_b(comp_ctx,
62014 DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A,
62015 (duk_regconst_t) args_truthval,
62016 (duk_regconst_t) reg_temp); /* skip jump conditionally */
62017 pc_jump = duk__emit_jump_empty(comp_ctx);
62018 duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
62019 duk__patch_jump_here(comp_ctx, pc_jump);
62020
62021 res->t = DUK_IVAL_PLAIN;
62022 res->x1.t = DUK_ISPEC_REGCONST;
62023 res->x1.regconst = (duk_regconst_t) reg_temp;
62024 return;
62025 }
62026
62027 assign:
62028 /*
62029 * Shared assignment expression handling
62030 *
62031 * args = (opcode << 8) + rbp
62032 *
62033 * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic.
62034 * Syntactically valid left-hand-side forms which are not accepted as
62035 * left-hand-side values (e.g. as in "f() = 1") must NOT cause a
62036 * SyntaxError, but rather a run-time ReferenceError.
62037 *
62038 * When evaluating X <op>= Y, the LHS (X) is conceptually evaluated
62039 * to a temporary first. The RHS is then evaluated. Finally, the
62040 * <op> is applied to the initial value of RHS (not the value after
62041 * RHS evaluation), and written to X. Doing so concretely generates
62042 * inefficient code so we'd like to avoid the temporary when possible.
62043 * See: https://github.com/svaarala/duktape/pull/992.
62044 *
62045 * The expression value (final LHS value, written to RHS) is
62046 * conceptually copied into a fresh temporary so that it won't
62047 * change even if the LHS/RHS values change in outer expressions.
62048 * For example, it'd be generally incorrect for the expression value
62049 * to be the RHS register binding, unless there's a guarantee that it
62050 * won't change during further expression evaluation. Using the
62051 * temporary concretely produces inefficient bytecode, so we try to
62052 * avoid the extra temporary for some known-to-be-safe cases.
62053 * Currently the only safe case we detect is a "top level assignment",
62054 * for example "x = y + z;", where the assignment expression value is
62055 * ignored.
62056 * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
62057 */
62058
62059 {
62060 duk_small_uint_t args_op = args >> 8;
62061 duk_small_uint_t args_rbp = args & 0xff;
62062 duk_bool_t toplevel_assign;
62063
62064 /* XXX: here we need to know if 'left' is left-hand-side compatible.
62065 * That information is no longer available from current expr parsing
62066 * state; it would need to be carried into the 'left' ivalue or by
62067 * some other means.
62068 */
62069
62070 /* A top-level assignment is e.g. "x = y;". For these it's safe
62071 * to use the RHS as-is as the expression value, even if the RHS
62072 * is a reg-bound identifier. The RHS ('res') is right associative
62073 * so it has consumed all other assignment level operations; the
62074 * only relevant lower binding power construct is comma operator
62075 * which will ignore the expression value provided here. Usually
62076 * the top level assignment expression value is ignored, but it
62077 * is relevant for e.g. eval code.
62078 */
62079 toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */
62080 comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */
62081 DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld",
62082 (long) comp_ctx->curr_func.nud_count,
62083 (long) comp_ctx->curr_func.led_count,
62084 (long) toplevel_assign));
62085
62086 if (left->t == DUK_IVAL_VAR) {
62087 duk_hstring *h_varname;
62088 duk_reg_t reg_varbind;
62089 duk_regconst_t rc_varname;
62090
62091 DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
62092
62093 h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
62094 DUK_ASSERT(h_varname != NULL);
62095 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
62096 /* E5 Section 11.13.1 (and others for other assignments), step 4. */
62097 goto syntax_error_lvalue;
62098 }
62099 duk_dup(ctx, left->x1.valstack_idx);
62100 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
62101
62102 if (args_op == DUK_OP_NONE) {
62103 duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
62104 if (toplevel_assign) {
62105 /* Any 'res' will do. */
62106 DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
62107 } else {
62108 /* 'res' must be a plain ivalue, and not register-bound variable. */
62109 DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
62110 if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
62111 (res->x1.regconst & DUK__CONST_MARKER) == 0 &&
62112 !DUK__ISTEMP(comp_ctx, res->x1.regconst))) {
62113 duk__ivalue_totempconst(comp_ctx, res);
62114 }
62115 }
62116 } else {
62117 /* For X <op>= Y we need to evaluate the pre-op
62118 * value of X before evaluating the RHS: the RHS
62119 * can change X, but when we do <op> we must use
62120 * the pre-op value.
62121 */
62122 duk_reg_t reg_temp;
62123
62124 reg_temp = DUK__ALLOCTEMP(comp_ctx);
62125
62126 if (reg_varbind >= 0) {
62127 duk_reg_t reg_res;
62128 duk_reg_t reg_src;
62129 duk_int_t pc_temp_load;
62130 duk_int_t pc_before_rhs;
62131 duk_int_t pc_after_rhs;
62132
62133 if (toplevel_assign) {
62134 /* 'reg_varbind' is the operation result and can also
62135 * become the expression value for top level assignments
62136 * such as: "var x; x += y;".
62137 */
62138 DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
62139 reg_res = reg_varbind;
62140 } else {
62141 /* Not safe to use 'reg_varbind' as assignment expression
62142 * value, so go through a temp.
62143 */
62144 DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp"));
62145 reg_res = reg_temp; /* reg_res should be smallest possible */
62146 reg_temp = DUK__ALLOCTEMP(comp_ctx);
62147 }
62148
62149 /* Try to optimize X <op>= Y for reg-bound
62150 * variables. Detect side-effect free RHS
62151 * narrowly by seeing whether it emits code.
62152 * If not, rewind the code emitter and overwrite
62153 * the unnecessary temp reg load.
62154 */
62155
62156 pc_temp_load = duk__get_current_pc(comp_ctx);
62157 duk__emit_a_bc(comp_ctx,
62158 DUK_OP_LDREG,
62159 (duk_regconst_t) reg_temp,
62160 reg_varbind);
62161
62162 pc_before_rhs = duk__get_current_pc(comp_ctx);
62163 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62164 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62165 pc_after_rhs = duk__get_current_pc(comp_ctx);
62166
62167 DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld",
62168 (long) pc_temp_load, (long) pc_before_rhs,
62169 (long) pc_after_rhs));
62170
62171 if (pc_after_rhs == pc_before_rhs) {
62172 /* Note: if the reg_temp load generated shuffling
62173 * instructions, we may need to rewind more than
62174 * one instruction, so use explicit PC computation.
62175 */
62176 DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
62177 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
62178 reg_src = reg_varbind;
62179 } else {
62180 DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
62181 reg_src = reg_temp;
62182 }
62183
62184 duk__emit_a_b_c(comp_ctx,
62185 args_op,
62186 (duk_regconst_t) reg_res,
62187 (duk_regconst_t) reg_src,
62188 res->x1.regconst);
62189
62190 res->x1.regconst = (duk_regconst_t) reg_res;
62191
62192 /* Ensure compact use of temps. */
62193 if (DUK__ISTEMP(comp_ctx, reg_res)) {
62194 DUK__SETTEMP(comp_ctx, reg_res + 1);
62195 }
62196 } else {
62197 /* When LHS is not register bound, always go through a
62198 * temporary. No optimization for top level assignment.
62199 */
62200
62201 duk__emit_a_bc(comp_ctx,
62202 DUK_OP_GETVAR,
62203 (duk_regconst_t) reg_temp,
62204 rc_varname);
62205
62206 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62207 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62208
62209 duk__emit_a_b_c(comp_ctx,
62210 args_op,
62211 (duk_regconst_t) reg_temp,
62212 (duk_regconst_t) reg_temp,
62213 res->x1.regconst);
62214 res->x1.regconst = (duk_regconst_t) reg_temp;
62215 }
62216
62217 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62218 }
62219
62220 /* At this point 'res' holds the potential expression value.
62221 * It can be basically any ivalue here, including a reg-bound
62222 * identifier (if code above deems it safe) or a unary/binary
62223 * operation. Operations must be resolved to a side effect free
62224 * plain value, and the side effects must happen exactly once.
62225 */
62226
62227 if (reg_varbind >= 0) {
62228 if (res->t != DUK_IVAL_PLAIN) {
62229 /* Resolve 'res' directly into the LHS binding, and use
62230 * that as the expression value if safe. If not safe,
62231 * resolve to a temp/const and copy to LHS.
62232 */
62233 if (toplevel_assign) {
62234 duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind);
62235 } else {
62236 duk__ivalue_totempconst(comp_ctx, res);
62237 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
62238 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
62239 }
62240 } else {
62241 /* Use 'res' as the expression value (it's side effect
62242 * free and may be a plain value, a register, or a
62243 * constant) and write it to the LHS binding too.
62244 */
62245 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
62246 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
62247 }
62248 } else {
62249 /* Only a reg fits into 'A' so coerce 'res' into a register
62250 * for PUTVAR.
62251 *
62252 * XXX: here the current A/B/C split is suboptimal: we could
62253 * just use 9 bits for reg_res (and support constants) and 17
62254 * instead of 18 bits for the varname const index.
62255 */
62256
62257 duk__ivalue_toreg(comp_ctx, res);
62258 duk__emit_a_bc(comp_ctx,
62259 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
62260 res->x1.regconst,
62261 rc_varname);
62262 }
62263
62264 /* 'res' contains expression value */
62265 } else if (left->t == DUK_IVAL_PROP) {
62266 /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
62267 duk_reg_t reg_obj;
62268 duk_regconst_t rc_key;
62269 duk_regconst_t rc_res;
62270 duk_reg_t reg_temp;
62271
62272 /* Property access expressions ('a[b]') are critical to correct
62273 * LHS evaluation ordering, see test-dev-assign-eval-order*.js.
62274 * We must make sure that the LHS target slot (base object and
62275 * key) don't change during RHS evaluation. The only concrete
62276 * problem is a register reference to a variable-bound register
62277 * (i.e., non-temp). Require temp regs for both key and base.
62278 *
62279 * Don't allow a constant for the object (even for a number
62280 * etc), as it goes into the 'A' field of the opcode.
62281 */
62282
62283 reg_obj = duk__ispec_toregconst_raw(comp_ctx,
62284 &left->x1,
62285 -1 /*forced_reg*/,
62286 DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
62287
62288 rc_key = duk__ispec_toregconst_raw(comp_ctx,
62289 &left->x2,
62290 -1 /*forced_reg*/,
62291 DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
62292
62293 /* Evaluate RHS only when LHS is safe. */
62294
62295 if (args_op == DUK_OP_NONE) {
62296 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62297 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62298 rc_res = res->x1.regconst;
62299 } else {
62300 reg_temp = DUK__ALLOCTEMP(comp_ctx);
62301 duk__emit_a_b_c(comp_ctx,
62302 DUK_OP_GETPROP,
62303 (duk_regconst_t) reg_temp,
62304 (duk_regconst_t) reg_obj,
62305 rc_key);
62306
62307 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62308 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62309
62310 duk__emit_a_b_c(comp_ctx,
62311 args_op,
62312 (duk_regconst_t) reg_temp,
62313 (duk_regconst_t) reg_temp,
62314 res->x1.regconst);
62315 rc_res = (duk_regconst_t) reg_temp;
62316 }
62317
62318 duk__emit_a_b_c(comp_ctx,
62319 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
62320 (duk_regconst_t) reg_obj,
62321 rc_key,
62322 rc_res);
62323
62324 res->t = DUK_IVAL_PLAIN;
62325 res->x1.t = DUK_ISPEC_REGCONST;
62326 res->x1.regconst = rc_res;
62327 } else {
62328 /* No support for lvalues returned from new or function call expressions.
62329 * However, these must NOT cause compile-time SyntaxErrors, but run-time
62330 * ReferenceErrors. Both left and right sides of the assignment must be
62331 * evaluated before throwing a ReferenceError. For instance:
62332 *
62333 * f() = g();
62334 *
62335 * must result in f() being evaluated, then g() being evaluated, and
62336 * finally, a ReferenceError being thrown. See E5 Section 11.13.1.
62337 */
62338
62339 duk_regconst_t rc_res;
62340
62341 /* First evaluate LHS fully to ensure all side effects are out. */
62342 duk__ivalue_toplain_ignore(comp_ctx, left);
62343
62344 /* Then evaluate RHS fully (its value becomes the expression value too).
62345 * Technically we'd need the side effect safety check here too, but because
62346 * we always throw using INVLHS the result doesn't matter.
62347 */
62348 rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62349
62350 duk__emit_extraop_only(comp_ctx,
62351 DUK_EXTRAOP_INVLHS);
62352
62353 res->t = DUK_IVAL_PLAIN;
62354 res->x1.t = DUK_ISPEC_REGCONST;
62355 res->x1.regconst = rc_res;
62356 }
62357
62358 return;
62359 }
62360
62361 postincdec:
62362 {
62363 /*
62364 * Post-increment/decrement will return the original value as its
62365 * result value. However, even that value will be coerced using
62366 * ToNumber() which is quite awkward. Specific bytecode opcodes
62367 * are used to handle these semantics.
62368 *
62369 * Note that post increment/decrement has a "no LineTerminator here"
62370 * restriction. This is handled by duk__expr_lbp(), which forcibly terminates
62371 * the previous expression if a LineTerminator occurs before '++'/'--'.
62372 */
62373
62374 duk_reg_t reg_res;
62375 duk_small_uint_t args_op = args >> 8;
62376
62377 /* Specific assumptions for opcode numbering. */
62378 DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV);
62379 DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV);
62380 DUK_ASSERT(DUK_OP_POSTINCR + 8 == DUK_OP_POSTINCP);
62381 DUK_ASSERT(DUK_OP_POSTDECR + 8 == DUK_OP_POSTDECP);
62382
62383 reg_res = DUK__ALLOCTEMP(comp_ctx);
62384
62385 if (left->t == DUK_IVAL_VAR) {
62386 duk_hstring *h_varname;
62387 duk_reg_t reg_varbind;
62388 duk_regconst_t rc_varname;
62389
62390 h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
62391 DUK_ASSERT(h_varname != NULL);
62392
62393 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
62394 goto syntax_error;
62395 }
62396
62397 duk_dup(ctx, left->x1.valstack_idx);
62398 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
62399 duk__emit_a_bc(comp_ctx,
62400 args_op, /* e.g. DUK_OP_POSTINCR */
62401 (duk_regconst_t) reg_res,
62402 (duk_regconst_t) reg_varbind);
62403 } else {
62404 duk__emit_a_bc(comp_ctx,
62405 args_op + 4, /* e.g. DUK_OP_POSTINCV */
62406 (duk_regconst_t) reg_res,
62407 rc_varname);
62408 }
62409
62410 DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
62411 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
62412 } else if (left->t == DUK_IVAL_PROP) {
62413 duk_reg_t reg_obj; /* allocate to reg only (not const) */
62414 duk_regconst_t rc_key;
62415
62416 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
62417 rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
62418 duk__emit_a_b_c(comp_ctx,
62419 args_op + 8, /* e.g. DUK_OP_POSTINCP */
62420 (duk_regconst_t) reg_res,
62421 (duk_regconst_t) reg_obj,
62422 rc_key);
62423 } else {
62424 /* Technically return value is not needed because INVLHS will
62425 * unconditially throw a ReferenceError. Coercion is necessary
62426 * for proper semantics (consider ToNumber() called for an object).
62427 * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
62428 */
62429 duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
62430 duk__emit_extraop_bc(comp_ctx,
62431 DUK_EXTRAOP_UNP,
62432 reg_res); /* for side effects, result ignored */
62433 duk__emit_extraop_only(comp_ctx,
62434 DUK_EXTRAOP_INVLHS);
62435 }
62436
62437 res->t = DUK_IVAL_PLAIN;
62438 res->x1.t = DUK_ISPEC_REGCONST;
62439 res->x1.regconst = (duk_regconst_t) reg_res;
62440 DUK__SETTEMP(comp_ctx, reg_res + 1);
62441 return;
62442 }
62443
62444 syntax_error:
62445 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
62446 return;
62447
62448 syntax_error_lvalue:
62449 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE);
62450 return;
62451}
62452
62453DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
62454 duk_small_int_t tok = comp_ctx->curr_token.t;
62455
62456 DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
62457 DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
62458
62459 /* XXX: integrate support for this into led() instead?
62460 * Similar issue as post-increment/post-decrement.
62461 */
62462
62463 /* prevent duk__expr_led() by using a binding power less than anything valid */
62464 if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) {
62465 return 0;
62466 }
62467
62468 if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) &&
62469 (comp_ctx->curr_token.lineterm)) {
62470 /* '++' or '--' in a post-increment/decrement position,
62471 * and a LineTerminator occurs between the operator and
62472 * the preceding expression. Force the previous expr
62473 * to terminate, in effect treating e.g. "a,b\n++" as
62474 * "a,b;++" (= SyntaxError).
62475 */
62476 return 0;
62477 }
62478
62479 return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */
62480}
62481
62482/*
62483 * Expression parsing.
62484 *
62485 * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
62486 * first token of the expression. Upon exit, 'curr_tok' will be the first
62487 * token not part of the expression (e.g. semicolon terminating an expression
62488 * statement).
62489 */
62490
62491#define DUK__EXPR_RBP_MASK 0xff
62492#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */
62493#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */
62494#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */
62495
62496/* main expression parser function */
62497DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62498 duk_hthread *thr = comp_ctx->thr;
62499 duk_context *ctx = (duk_context *) thr;
62500 duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */
62501 duk_ivalue *tmp = &tmp_alloc;
62502 duk_small_uint_t rbp;
62503
62504 DUK__RECURSION_INCREASE(comp_ctx, thr);
62505
62506 duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
62507
62508 /* filter out flags from exprtop rbp_flags here to save space */
62509 rbp = rbp_flags & DUK__EXPR_RBP_MASK;
62510
62511 DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld",
62512 (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in,
62513 (long) comp_ctx->curr_func.paren_level));
62514
62515 DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc));
62516 tmp->x1.valstack_idx = duk_get_top(ctx);
62517 tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
62518 duk_push_undefined(ctx);
62519 duk_push_undefined(ctx);
62520
62521 /* XXX: where to release temp regs in intermediate expressions?
62522 * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
62523 * that particular expression temp regs can be forced here.
62524 */
62525
62526 /* XXX: increase ctx->expr_tokens here for every consumed token
62527 * (this would be a nice statistic)?
62528 */
62529
62530 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
62531 /* XXX: possibly incorrect handling of empty expression */
62532 DUK_DDD(DUK_DDDPRINT("empty expression"));
62533 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
62534 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
62535 }
62536 res->t = DUK_IVAL_PLAIN;
62537 res->x1.t = DUK_ISPEC_VALUE;
62538 duk_push_undefined(ctx);
62539 duk_replace(ctx, res->x1.valstack_idx);
62540 goto cleanup;
62541 }
62542
62543 duk__advance(comp_ctx);
62544 duk__expr_nud(comp_ctx, res); /* reuse 'res' as 'left' */
62545 while (rbp < duk__expr_lbp(comp_ctx)) {
62546 duk__advance(comp_ctx);
62547 duk__expr_led(comp_ctx, res, tmp);
62548 duk__copy_ivalue(comp_ctx, tmp, res); /* tmp -> res */
62549 }
62550
62551 cleanup:
62552 /* final result is already in 'res' */
62553
62554 duk_pop_2(ctx);
62555
62556 DUK__RECURSION_DECREASE(comp_ctx, thr);
62557}
62558
62559DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62560 duk_hthread *thr = comp_ctx->thr;
62561
62562 /* Note: these variables must reside in 'curr_func' instead of the global
62563 * context: when parsing function expressions, expression parsing is nested.
62564 */
62565 comp_ctx->curr_func.nud_count = 0;
62566 comp_ctx->curr_func.led_count = 0;
62567 comp_ctx->curr_func.paren_level = 0;
62568 comp_ctx->curr_func.expr_lhs = 1;
62569 comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1);
62570
62571 duk__expr(comp_ctx, res, rbp_flags);
62572
62573 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) {
62574 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
62575 }
62576}
62577
62578/* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
62579 * and result conversions.
62580 *
62581 * Each helper needs at least 2-3 calls to make it worth while to wrap.
62582 */
62583
62584#if 0 /* unused */
62585DUK_LOCAL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62586 duk__expr(comp_ctx, res, rbp_flags);
62587 return duk__ivalue_toreg(comp_ctx, res);
62588}
62589#endif
62590
62591#if 0 /* unused */
62592DUK_LOCAL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62593 duk__expr(comp_ctx, res, rbp_flags);
62594 return duk__ivalue_totemp(comp_ctx, res);
62595}
62596#endif
62597
62598DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
62599 DUK_ASSERT(forced_reg >= 0);
62600 duk__expr(comp_ctx, res, rbp_flags);
62601 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
62602}
62603
62604DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62605 duk__expr(comp_ctx, res, rbp_flags);
62606 return duk__ivalue_toregconst(comp_ctx, res);
62607}
62608
62609#if 0 /* unused */
62610DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62611 duk__expr(comp_ctx, res, rbp_flags);
62612 return duk__ivalue_totempconst(comp_ctx, res);
62613}
62614#endif
62615
62616DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62617 duk__expr(comp_ctx, res, rbp_flags);
62618 duk__ivalue_toplain(comp_ctx, res);
62619}
62620
62621DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62622 duk__expr(comp_ctx, res, rbp_flags);
62623 duk__ivalue_toplain_ignore(comp_ctx, res);
62624}
62625
62626DUK_LOCAL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62627 duk__exprtop(comp_ctx, res, rbp_flags);
62628 return duk__ivalue_toreg(comp_ctx, res);
62629}
62630
62631#if 0 /* unused */
62632DUK_LOCAL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62633 duk__exprtop(comp_ctx, res, rbp_flags);
62634 return duk__ivalue_totemp(comp_ctx, res);
62635}
62636#endif
62637
62638DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
62639 DUK_ASSERT(forced_reg >= 0);
62640 duk__exprtop(comp_ctx, res, rbp_flags);
62641 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
62642}
62643
62644DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62645 duk__exprtop(comp_ctx, res, rbp_flags);
62646 return duk__ivalue_toregconst(comp_ctx, res);
62647}
62648
62649#if 0 /* unused */
62650DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
62651 duk__exprtop(comp_ctx, res, rbp_flags);
62652 duk__ivalue_toplain_ignore(comp_ctx, res);
62653}
62654#endif
62655
62656/*
62657 * Parse an individual source element (top level statement) or a statement.
62658 *
62659 * Handles labeled statements automatically (peeling away labels before
62660 * parsing an expression that follows the label(s)).
62661 *
62662 * Upon entry, 'curr_tok' contains the first token of the statement (parsed
62663 * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first
62664 * token following the statement (if the statement has a terminator, this is
62665 * the token after the terminator).
62666 */
62667
62668#ifdef DUK__HAS_VAL
62669#undef DUK__HAS_VAL
62670#endif
62671#ifdef DUK__HAS_TERM
62672#undef DUK__HAS_TERM
62673#endif
62674#ifdef DUK__ALLOW_AUTO_SEMI_ALWAYS
62675#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
62676#endif
62677#ifdef DUK__STILL_PROLOGUE
62678#undef DUK__STILL_PROLOGUE
62679#endif
62680#ifdef DUK__IS_TERMINAL
62681#undef DUK__IS_TERMINAL
62682#endif
62683
62684#define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */
62685#define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */
62686#define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */
62687#define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */
62688#define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
62689
62690/* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var'
62691 * has already been eaten. These is no return value in 'res', it is used only
62692 * as a temporary.
62693 *
62694 * When called from 'for-in' statement parser, the initializer expression must
62695 * not allow the 'in' token. The caller supply additional expression parsing
62696 * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
62697 *
62698 * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
62699 * the identifier is bound:
62700 *
62701 * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore)
62702 * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0
62703 *
62704 * These allow the caller to use the variable for further assignment, e.g.
62705 * as is done in 'for-in' parsing.
62706 */
62707
62708DUK_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) {
62709 duk_hthread *thr = comp_ctx->thr;
62710 duk_context *ctx = (duk_context *) thr;
62711 duk_hstring *h_varname;
62712 duk_reg_t reg_varbind;
62713 duk_regconst_t rc_varname;
62714
62715 /* assume 'var' has been eaten */
62716
62717 /* Note: Identifier rejects reserved words */
62718 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
62719 goto syntax_error;
62720 }
62721 h_varname = comp_ctx->curr_token.str1;
62722
62723 DUK_ASSERT(h_varname != NULL);
62724
62725 /* strict mode restrictions (E5 Section 12.2.1) */
62726 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
62727 goto syntax_error;
62728 }
62729
62730 /* register declarations in first pass */
62731 if (comp_ctx->curr_func.in_scanning) {
62732 duk_uarridx_t n;
62733 DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
62734 (duk_heaphdr *) h_varname));
62735 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
62736 duk_push_hstring(ctx, h_varname);
62737 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
62738 duk_push_int(ctx, DUK_DECL_TYPE_VAR + (0 << 8));
62739 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
62740 }
62741
62742 duk_push_hstring(ctx, h_varname); /* push before advancing to keep reachable */
62743
62744 /* register binding lookup is based on varmap (even in first pass) */
62745 duk_dup_top(ctx);
62746 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
62747
62748 duk__advance(comp_ctx); /* eat identifier */
62749
62750 if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
62751 duk__advance(comp_ctx);
62752
62753 DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
62754 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
62755
62756 duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */
62757
62758 if (reg_varbind >= 0) {
62759 duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
62760 } else {
62761 duk_reg_t reg_val;
62762 reg_val = duk__ivalue_toreg(comp_ctx, res);
62763 duk__emit_a_bc(comp_ctx,
62764 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
62765 (duk_regconst_t) reg_val,
62766 rc_varname);
62767 }
62768 } else {
62769 if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
62770 /* Used for minimal 'const': initializer required. */
62771 goto syntax_error;
62772 }
62773 }
62774
62775 duk_pop(ctx); /* pop varname */
62776
62777 *out_rc_varname = rc_varname;
62778 *out_reg_varbind = reg_varbind;
62779
62780 return;
62781
62782 syntax_error:
62783 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION);
62784}
62785
62786DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
62787 duk_reg_t reg_varbind;
62788 duk_regconst_t rc_varname;
62789
62790 duk__advance(comp_ctx); /* eat 'var' */
62791
62792 for (;;) {
62793 /* rc_varname and reg_varbind are ignored here */
62794 duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
62795
62796 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
62797 break;
62798 }
62799 duk__advance(comp_ctx);
62800 }
62801}
62802
62803DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
62804 duk_hthread *thr = comp_ctx->thr;
62805 duk_context *ctx = (duk_context *) thr;
62806 duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
62807 duk_reg_t temp_reset; /* knock back "next temp" to this whenever possible */
62808 duk_reg_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
62809
62810 DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
62811
62812 /* Two temporaries are preallocated here for variants 3 and 4 which need
62813 * registers which are never clobbered by expressions in the loop
62814 * (concretely: for the enumerator object and the next enumerated value).
62815 * Variants 1 and 2 "release" these temps.
62816 */
62817
62818 reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
62819
62820 temp_reset = DUK__GETTEMP(comp_ctx);
62821
62822 /*
62823 * For/for-in main variants are:
62824 *
62825 * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
62826 * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
62827 * 3. for (LeftHandSideExpression in Expression) Statement
62828 * 4. for (var VariableDeclarationNoIn in Expression) Statement
62829 *
62830 * Parsing these without arbitrary lookahead or backtracking is relatively
62831 * tricky but we manage to do so for now.
62832 *
62833 * See doc/compiler.rst for a detailed discussion of control flow
62834 * issues, evaluation order issues, etc.
62835 */
62836
62837 duk__advance(comp_ctx); /* eat 'for' */
62838 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
62839
62840 DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx)));
62841
62842 /* a label site has been emitted by duk__parse_stmt() automatically
62843 * (it will also emit the ENDLABEL).
62844 */
62845
62846 if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
62847 /*
62848 * Variant 2 or 4
62849 */
62850
62851 duk_reg_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
62852 duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */
62853
62854 duk__advance(comp_ctx); /* eat 'var' */
62855 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
62856 DUK__SETTEMP(comp_ctx, temp_reset);
62857
62858 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
62859 /*
62860 * Variant 4
62861 */
62862
62863 DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement"));
62864 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here */
62865 if (reg_varbind >= 0) {
62866 duk__emit_a_bc(comp_ctx,
62867 DUK_OP_LDREG,
62868 (duk_regconst_t) reg_varbind,
62869 (duk_regconst_t) (reg_temps + 0));
62870 } else {
62871 duk__emit_a_bc(comp_ctx,
62872 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
62873 (duk_regconst_t) (reg_temps + 0),
62874 rc_varname);
62875 }
62876 goto parse_3_or_4;
62877 } else {
62878 /*
62879 * Variant 2
62880 */
62881
62882 DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
62883 for (;;) {
62884 /* more initializers */
62885 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
62886 break;
62887 }
62888 DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
62889
62890 duk__advance(comp_ctx); /* eat comma */
62891 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
62892 }
62893 goto parse_1_or_2;
62894 }
62895 } else {
62896 /*
62897 * Variant 1 or 3
62898 */
62899
62900 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */
62901
62902 /* Note that duk__exprtop() here can clobber any reg above current temp_next,
62903 * so any loop variables (e.g. enumerator) must be "preallocated".
62904 */
62905
62906 /* don't coerce yet to a plain value (variant 3 needs special handling) */
62907 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression */
62908 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
62909 /*
62910 * Variant 3
62911 */
62912
62913 /* XXX: need to determine LHS type, and check that it is LHS compatible */
62914 DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement"));
62915 if (duk__expr_is_empty(comp_ctx)) {
62916 goto syntax_error; /* LeftHandSideExpression does not allow empty expression */
62917 }
62918
62919 if (res->t == DUK_IVAL_VAR) {
62920 duk_reg_t reg_varbind;
62921 duk_regconst_t rc_varname;
62922
62923 duk_dup(ctx, res->x1.valstack_idx);
62924 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
62925 duk__emit_a_bc(comp_ctx,
62926 DUK_OP_LDREG,
62927 (duk_regconst_t) reg_varbind,
62928 (duk_regconst_t) (reg_temps + 0));
62929 } else {
62930 duk__emit_a_bc(comp_ctx,
62931 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
62932 (duk_regconst_t) (reg_temps + 0),
62933 rc_varname);
62934 }
62935 } else if (res->t == DUK_IVAL_PROP) {
62936 /* Don't allow a constant for the object (even for a number etc), as
62937 * it goes into the 'A' field of the opcode.
62938 */
62939 duk_reg_t reg_obj;
62940 duk_regconst_t rc_key;
62941 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
62942 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
62943 duk__emit_a_b_c(comp_ctx,
62944 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
62945 (duk_regconst_t) reg_obj,
62946 rc_key,
62947 (duk_regconst_t) (reg_temps + 0));
62948 } else {
62949 duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
62950 duk__emit_extraop_only(comp_ctx,
62951 DUK_EXTRAOP_INVLHS);
62952 }
62953 goto parse_3_or_4;
62954 } else {
62955 /*
62956 * Variant 1
62957 */
62958
62959 DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement"));
62960 duk__ivalue_toplain_ignore(comp_ctx, res);
62961 goto parse_1_or_2;
62962 }
62963 }
62964
62965 parse_1_or_2:
62966 /*
62967 * Parse variant 1 or 2. The first part expression (which differs
62968 * in the variants) has already been parsed and its code emitted.
62969 *
62970 * reg_temps + 0: unused
62971 * reg_temps + 1: unused
62972 */
62973 {
62974 duk_regconst_t rc_cond;
62975 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4;
62976 duk_int_t pc_jumpto_l3, pc_jumpto_l4;
62977 duk_bool_t expr_c_empty;
62978
62979 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
62980
62981 /* "release" preallocated temps since we won't need them */
62982 temp_reset = reg_temps + 0;
62983 DUK__SETTEMP(comp_ctx, temp_reset);
62984
62985 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
62986
62987 pc_l1 = duk__get_current_pc(comp_ctx);
62988 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
62989 if (duk__expr_is_empty(comp_ctx)) {
62990 /* no need to coerce */
62991 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
62992 pc_jumpto_l4 = -1; /* omitted */
62993 } else {
62994 rc_cond = duk__ivalue_toregconst(comp_ctx, res);
62995 duk__emit_if_false_skip(comp_ctx, rc_cond);
62996 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
62997 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); /* to exit */
62998 }
62999 DUK__SETTEMP(comp_ctx, temp_reset);
63000
63001 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
63002
63003 pc_l2 = duk__get_current_pc(comp_ctx);
63004 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
63005 if (duk__expr_is_empty(comp_ctx)) {
63006 /* no need to coerce */
63007 expr_c_empty = 1;
63008 /* JUMP L1 omitted */
63009 } else {
63010 duk__ivalue_toplain_ignore(comp_ctx, res);
63011 expr_c_empty = 0;
63012 duk__emit_jump(comp_ctx, pc_l1);
63013 }
63014 DUK__SETTEMP(comp_ctx, temp_reset);
63015
63016 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63017
63018 pc_l3 = duk__get_current_pc(comp_ctx);
63019 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63020 if (expr_c_empty) {
63021 duk__emit_jump(comp_ctx, pc_l1);
63022 } else {
63023 duk__emit_jump(comp_ctx, pc_l2);
63024 }
63025 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
63026
63027 pc_l4 = duk__get_current_pc(comp_ctx);
63028
63029 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, "
63030 "break: %ld->%ld, continue: %ld->%ld",
63031 (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4,
63032 (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2));
63033
63034 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
63035 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
63036 duk__patch_jump(comp_ctx,
63037 pc_label_site + 1,
63038 pc_l4); /* break jump */
63039 duk__patch_jump(comp_ctx,
63040 pc_label_site + 2,
63041 expr_c_empty ? pc_l1 : pc_l2); /* continue jump */
63042 }
63043 goto finished;
63044
63045 parse_3_or_4:
63046 /*
63047 * Parse variant 3 or 4.
63048 *
63049 * For variant 3 (e.g. "for (A in C) D;") the code for A (except the
63050 * final property/variable write) has already been emitted. The first
63051 * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
63052 * there to satisfy control flow needs.
63053 *
63054 * For variant 4, if the variable declaration had an initializer
63055 * (e.g. "for (var A = B in C) D;") the code for the assignment
63056 * (B) has already been emitted.
63057 *
63058 * Variables set before entering here:
63059 *
63060 * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example).
63061 * reg_temps + 0: iteration target value (written to LHS)
63062 * reg_temps + 1: enumerator object
63063 */
63064 {
63065 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
63066 duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
63067 duk_reg_t reg_target;
63068
63069 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
63070
63071 DUK__SETTEMP(comp_ctx, temp_reset);
63072
63073 /* First we need to insert a jump in the middle of previously
63074 * emitted code to get the control flow right. No jumps can
63075 * cross the position where the jump is inserted. See doc/compiler.rst
63076 * for discussion on the intricacies of control flow and side effects
63077 * for variants 3 and 4.
63078 */
63079
63080 duk__insert_jump_entry(comp_ctx, pc_v34_lhs);
63081 pc_jumpto_l2 = pc_v34_lhs; /* inserted jump */
63082 pc_l1 = pc_v34_lhs + 1; /* +1, right after inserted jump */
63083
63084 /* The code for writing reg_temps + 0 to the left hand side has already
63085 * been emitted.
63086 */
63087
63088 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */
63089
63090 duk__advance(comp_ctx); /* eat 'in' */
63091
63092 /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined',
63093 * INITENUM will creates a 'null' enumerator which works like an empty enumerator
63094 * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a
63095 * register (constant not allowed).
63096 */
63097
63098 pc_l2 = duk__get_current_pc(comp_ctx);
63099 reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */
63100 duk__emit_extraop_b_c(comp_ctx,
63101 DUK_EXTRAOP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
63102 (duk_regconst_t) (reg_temps + 1),
63103 (duk_regconst_t) reg_target);
63104 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
63105 DUK__SETTEMP(comp_ctx, temp_reset);
63106
63107 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63108
63109 pc_l3 = duk__get_current_pc(comp_ctx);
63110 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63111 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
63112
63113 /* NEXTENUM needs a jump slot right after the main opcode.
63114 * We need the code emitter to reserve the slot: if there's
63115 * target shuffling, the target shuffle opcodes must happen
63116 * after the jump slot (for NEXTENUM the shuffle opcodes are
63117 * not needed if the enum is finished).
63118 */
63119 pc_l4 = duk__get_current_pc(comp_ctx);
63120 duk__emit_extraop_b_c(comp_ctx,
63121 DUK_EXTRAOP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
63122 (duk_regconst_t) (reg_temps + 0),
63123 (duk_regconst_t) (reg_temps + 1));
63124 pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */
63125 duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */
63126
63127 pc_l5 = duk__get_current_pc(comp_ctx);
63128
63129 /* XXX: since the enumerator may be a memory expensive object,
63130 * perhaps clear it explicitly here? If so, break jump must
63131 * go through this clearing operation.
63132 */
63133
63134 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, "
63135 "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, "
63136 "break: %ld->%ld, continue: %ld->%ld",
63137 (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3,
63138 (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5,
63139 (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4));
63140
63141 duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2);
63142 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
63143 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
63144 duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5);
63145 duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5); /* break jump */
63146 duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4); /* continue jump */
63147 }
63148 goto finished;
63149
63150 finished:
63151 DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
63152 return;
63153
63154 syntax_error:
63155 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR);
63156}
63157
63158DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
63159 duk_hthread *thr = comp_ctx->thr;
63160 duk_reg_t temp_at_loop;
63161 duk_regconst_t rc_switch; /* reg/const for switch value */
63162 duk_regconst_t rc_case; /* reg/const for case value */
63163 duk_reg_t reg_temp; /* general temp register */
63164 duk_int_t pc_prevcase = -1;
63165 duk_int_t pc_prevstmt = -1;
63166 duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */
63167
63168 /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
63169
63170 /*
63171 * Switch is pretty complicated because of several conflicting concerns:
63172 *
63173 * - Want to generate code without an intermediate representation,
63174 * i.e., in one go
63175 *
63176 * - Case selectors are expressions, not values, and may thus e.g. throw
63177 * exceptions (which causes evaluation order concerns)
63178 *
63179 * - Evaluation semantics of case selectors and default clause need to be
63180 * carefully implemented to provide correct behavior even with case value
63181 * side effects
63182 *
63183 * - Fall through case and default clauses; avoiding dead JUMPs if case
63184 * ends with an unconditional jump (a break or a continue)
63185 *
63186 * - The same case value may occur multiple times, but evaluation rules
63187 * only process the first match before switching to a "propagation" mode
63188 * where case values are no longer evaluated
63189 *
63190 * See E5 Section 12.11. Also see doc/compiler.rst for compilation
63191 * discussion.
63192 */
63193
63194 duk__advance(comp_ctx);
63195 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63196 rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63197 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63198 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63199
63200 DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch));
63201
63202 temp_at_loop = DUK__GETTEMP(comp_ctx);
63203
63204 for (;;) {
63205 duk_int_t num_stmts;
63206 duk_small_int_t tok;
63207
63208 /* sufficient for keeping temp reg numbers in check */
63209 DUK__SETTEMP(comp_ctx, temp_at_loop);
63210
63211 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
63212 break;
63213 }
63214
63215 /*
63216 * Parse a case or default clause.
63217 */
63218
63219 if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
63220 /*
63221 * Case clause.
63222 *
63223 * Note: cannot use reg_case as a temp register (for SEQ target)
63224 * because it may be a constant.
63225 */
63226
63227 duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case
63228 * evaluation and checking
63229 */
63230
63231 duk__advance(comp_ctx);
63232 rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63233 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
63234
63235 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63236 duk__emit_a_b_c(comp_ctx,
63237 DUK_OP_SEQ,
63238 (duk_regconst_t) reg_temp,
63239 rc_switch,
63240 rc_case);
63241 duk__emit_if_true_skip(comp_ctx, (duk_regconst_t) reg_temp);
63242
63243 /* jump to next case clause */
63244 pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
63245
63246 /* statements go here (if any) on next loop */
63247 } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
63248 /*
63249 * Default clause.
63250 */
63251
63252 if (pc_default >= 0) {
63253 goto syntax_error;
63254 }
63255 duk__advance(comp_ctx);
63256 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
63257
63258 /* Fix for https://github.com/svaarala/duktape/issues/155:
63259 * If 'default' is first clause (detected by pc_prevcase < 0)
63260 * we need to ensure we stay in the matching chain.
63261 */
63262 if (pc_prevcase < 0) {
63263 DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump"));
63264 pc_prevcase = duk__emit_jump_empty(comp_ctx);
63265 }
63266
63267 /* default clause matches next statement list (if any) */
63268 pc_default = -2;
63269 } else {
63270 /* Code is not accepted before the first case/default clause */
63271 goto syntax_error;
63272 }
63273
63274 /*
63275 * Parse code after the clause. Possible terminators are
63276 * 'case', 'default', and '}'.
63277 *
63278 * Note that there may be no code at all, not even an empty statement,
63279 * between case clauses. This must be handled just like an empty statement
63280 * (omitting seemingly pointless JUMPs), to avoid situations like
63281 * test-bug-case-fallthrough.js.
63282 */
63283
63284 num_stmts = 0;
63285 if (pc_default == -2) {
63286 pc_default = duk__get_current_pc(comp_ctx);
63287 }
63288
63289 /* Note: this is correct even for default clause statements:
63290 * they participate in 'fall-through' behavior even if the
63291 * default clause is in the middle.
63292 */
63293 duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through'
63294 * after a case matches.
63295 */
63296
63297 for (;;) {
63298 tok = comp_ctx->curr_token.t;
63299 if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
63300 tok == DUK_TOK_RCURLY) {
63301 break;
63302 }
63303 num_stmts++;
63304 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63305 }
63306
63307 /* fall-through jump to next code of next case (backpatched) */
63308 pc_prevstmt = duk__emit_jump_empty(comp_ctx);
63309
63310 /* XXX: would be nice to omit this jump when the jump is not
63311 * reachable, at least in the obvious cases (such as the case
63312 * ending with a 'break'.
63313 *
63314 * Perhaps duk__parse_stmt() could provide some info on whether
63315 * the statement is a "dead end"?
63316 *
63317 * If implemented, just set pc_prevstmt to -1 when not needed.
63318 */
63319 }
63320
63321 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
63322 duk__advance(comp_ctx);
63323
63324 /* default case control flow patchup; note that if pc_prevcase < 0
63325 * (i.e. no case clauses), control enters default case automatically.
63326 */
63327 if (pc_default >= 0) {
63328 /* default case exists: go there if no case matches */
63329 duk__patch_jump(comp_ctx, pc_prevcase, pc_default);
63330 } else {
63331 /* default case does not exist, or no statements present
63332 * after default case: finish case evaluation
63333 */
63334 duk__patch_jump_here(comp_ctx, pc_prevcase);
63335 }
63336
63337 /* fall-through control flow patchup; note that pc_prevstmt may be
63338 * < 0 (i.e. no case clauses), in which case this is a no-op.
63339 */
63340 duk__patch_jump_here(comp_ctx, pc_prevstmt);
63341
63342 /* continue jump not patched, an INVALID opcode remains there */
63343 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
63344
63345 /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
63346 * then jump here. The double jump will be eliminated by a
63347 * peephole pass, resulting in an optimal jump here. The label
63348 * site jumps will remain in bytecode and will waste code size.
63349 */
63350
63351 return;
63352
63353 syntax_error:
63354 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH);
63355}
63356
63357DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63358 duk_reg_t temp_reset;
63359 duk_regconst_t rc_cond;
63360 duk_int_t pc_jump_false;
63361
63362 DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
63363
63364 temp_reset = DUK__GETTEMP(comp_ctx);
63365
63366 duk__advance(comp_ctx); /* eat 'if' */
63367 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63368
63369 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63370 duk__emit_if_true_skip(comp_ctx, rc_cond);
63371 pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */
63372 DUK__SETTEMP(comp_ctx, temp_reset);
63373
63374 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63375
63376 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63377
63378 /* The 'else' ambiguity is resolved by 'else' binding to the innermost
63379 * construct, so greedy matching is correct here.
63380 */
63381
63382 if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
63383 duk_int_t pc_jump_end;
63384
63385 DUK_DDD(DUK_DDDPRINT("if has else part"));
63386
63387 duk__advance(comp_ctx);
63388
63389 pc_jump_end = duk__emit_jump_empty(comp_ctx); /* jump from true part to end */
63390 duk__patch_jump_here(comp_ctx, pc_jump_false);
63391
63392 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63393
63394 duk__patch_jump_here(comp_ctx, pc_jump_end);
63395 } else {
63396 DUK_DDD(DUK_DDDPRINT("if does not have else part"));
63397
63398 duk__patch_jump_here(comp_ctx, pc_jump_false);
63399 }
63400
63401 DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
63402}
63403
63404DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
63405 duk_regconst_t rc_cond;
63406 duk_int_t pc_start;
63407
63408 DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
63409
63410 duk__advance(comp_ctx); /* eat 'do' */
63411
63412 pc_start = duk__get_current_pc(comp_ctx);
63413 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63414 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
63415
63416 duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
63417 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63418
63419 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63420 duk__emit_if_false_skip(comp_ctx, rc_cond);
63421 duk__emit_jump(comp_ctx, pc_start);
63422 /* no need to reset temps, as we're finished emitting code */
63423
63424 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63425
63426 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
63427
63428 DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
63429}
63430
63431DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
63432 duk_reg_t temp_reset;
63433 duk_regconst_t rc_cond;
63434 duk_int_t pc_start;
63435 duk_int_t pc_jump_false;
63436
63437 DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
63438
63439 temp_reset = DUK__GETTEMP(comp_ctx);
63440
63441 duk__advance(comp_ctx); /* eat 'while' */
63442
63443 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63444
63445 pc_start = duk__get_current_pc(comp_ctx);
63446 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
63447
63448 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63449 duk__emit_if_true_skip(comp_ctx, rc_cond);
63450 pc_jump_false = duk__emit_jump_empty(comp_ctx);
63451 DUK__SETTEMP(comp_ctx, temp_reset);
63452
63453 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63454
63455 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63456 duk__emit_jump(comp_ctx, pc_start);
63457
63458 duk__patch_jump_here(comp_ctx, pc_jump_false);
63459 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
63460
63461 DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
63462}
63463
63464DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63465 duk_hthread *thr = comp_ctx->thr;
63466 duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK);
63467 duk_int_t label_id;
63468 duk_int_t label_catch_depth;
63469 duk_int_t label_pc; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
63470 duk_bool_t label_is_closest;
63471
63472 DUK_UNREF(res);
63473
63474 duk__advance(comp_ctx); /* eat 'break' or 'continue' */
63475
63476 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
63477 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
63478 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
63479 /* break/continue without label */
63480
63481 duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
63482 } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) {
63483 /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
63484 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
63485 duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
63486 duk__advance(comp_ctx);
63487 } else {
63488 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL);
63489 }
63490
63491 /* Use a fast break/continue when possible. A fast break/continue is
63492 * just a jump to the LABEL break/continue jump slot, which then jumps
63493 * to an appropriate place (for break, going through ENDLABEL correctly).
63494 * The peephole optimizer will optimize the jump to a direct one.
63495 */
63496
63497 if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
63498 label_is_closest) {
63499 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
63500 "label_catch_depth=%ld, catch_depth=%ld "
63501 "-> use fast variant (direct jump)",
63502 (long) is_break, (long) label_id, (long) label_is_closest,
63503 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
63504
63505 duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
63506 } else {
63507 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
63508 "label_catch_depth=%ld, catch_depth=%ld "
63509 "-> use slow variant (longjmp)",
63510 (long) is_break, (long) label_id, (long) label_is_closest,
63511 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
63512
63513 duk__emit_extraop_bc(comp_ctx,
63514 is_break ? DUK_EXTRAOP_BREAK : DUK_EXTRAOP_CONTINUE,
63515 (duk_regconst_t) label_id);
63516 }
63517}
63518
63519DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63520 duk_hthread *thr = comp_ctx->thr;
63521 duk_regconst_t rc_val;
63522 duk_small_uint_t ret_flags;
63523
63524 duk__advance(comp_ctx); /* eat 'return' */
63525
63526 /* A 'return' statement is only allowed inside an actual function body,
63527 * not as part of eval or global code.
63528 */
63529 if (!comp_ctx->curr_func.is_function) {
63530 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
63531 }
63532
63533 ret_flags = 0;
63534
63535 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
63536 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
63537 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
63538 DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
63539 rc_val = 0;
63540 } else {
63541 duk_int_t pc_before_expr;
63542 duk_int_t pc_after_expr;
63543
63544 DUK_DDD(DUK_DDDPRINT("return with a value"));
63545
63546 DUK_UNREF(pc_before_expr);
63547 DUK_UNREF(pc_after_expr);
63548
63549 pc_before_expr = duk__get_current_pc(comp_ctx);
63550 rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63551 pc_after_expr = duk__get_current_pc(comp_ctx);
63552
63553 /* Tail call check: if last opcode emitted was CALL(I), and
63554 * the context allows it, change the CALL(I) to a tail call.
63555 * This doesn't guarantee that a tail call will be allowed at
63556 * runtime, so the RETURN must still be emitted. (Duktape
63557 * 0.10.0 avoided this and simulated a RETURN if a tail call
63558 * couldn't be used at runtime; but this didn't work
63559 * correctly with a thread yield/resume, see
63560 * test-bug-tailcall-thread-yield-resume.js for discussion.)
63561 *
63562 * In addition to the last opcode being CALL, we also need to
63563 * be sure that 'rc_val' is the result register of the CALL(I).
63564 * For instance, for the expression 'return 0, (function ()
63565 * { return 1; }), 2' the last opcode emitted is CALL (no
63566 * bytecode is emitted for '2') but 'rc_val' indicates
63567 * constant '2'. Similarly if '2' is replaced by a register
63568 * bound variable, no opcodes are emitted but tail call would
63569 * be incorrect.
63570 *
63571 * This is tricky and easy to get wrong. It would be best to
63572 * track enough expression metadata to check that 'rc_val' came
63573 * from that last CALL instruction. We don't have that metadata
63574 * now, so we check that 'rc_val' is a temporary register result
63575 * (not a constant or a register bound variable). There should
63576 * be no way currently for 'rc_val' to be a temporary for an
63577 * expression following the CALL instruction without emitting
63578 * some opcodes following the CALL. This proxy check is used
63579 * below.
63580 *
63581 * See: test-bug-comma-expr-gh131.js.
63582 *
63583 * The non-standard 'caller' property disables tail calls
63584 * because they pose some special cases which haven't been
63585 * fixed yet.
63586 */
63587
63588#if defined(DUK_USE_TAILCALL)
63589 if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */
63590 pc_after_expr > pc_before_expr) { /* at least one opcode emitted */
63591 duk_compiler_instr *instr;
63592 duk_small_uint_t op;
63593
63594 instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
63595 DUK_ASSERT(instr != NULL);
63596
63597 op = (duk_small_uint_t) DUK_DEC_OP(instr->ins);
63598 if ((op == DUK_OP_CALL || op == DUK_OP_CALLI) &&
63599 DUK__ISTEMP(comp_ctx, rc_val) /* see above */) {
63600 DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
63601 "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
63602 "and last instruction is a CALL "
63603 "-> set TAILCALL flag"));
63604 /* Just flip the single bit. */
63605 instr->ins |= DUK_ENC_OP_A_B_C(0, DUK_BC_CALL_FLAG_TAILCALL, 0, 0);
63606 }
63607 }
63608#endif /* DUK_USE_TAILCALL */
63609
63610 ret_flags = DUK_BC_RETURN_FLAG_HAVE_RETVAL;
63611 }
63612
63613 duk__emit_a_b(comp_ctx,
63614 DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
63615 (duk_regconst_t) ret_flags /*flags*/,
63616 rc_val /*reg*/);
63617}
63618
63619DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63620 duk_reg_t reg_val;
63621
63622 duk__advance(comp_ctx); /* eat 'throw' */
63623
63624 /* Unlike break/continue, throw statement does not allow an empty value. */
63625
63626 if (comp_ctx->curr_token.lineterm) {
63627 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW);
63628 }
63629
63630 reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63631 duk__emit_extraop_bc(comp_ctx,
63632 DUK_EXTRAOP_THROW,
63633 (duk_regconst_t) reg_val);
63634}
63635
63636DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63637 duk_hthread *thr = comp_ctx->thr;
63638 duk_context *ctx = (duk_context *) thr;
63639 duk_reg_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
63640 duk_regconst_t rc_varname = 0;
63641 duk_small_uint_t trycatch_flags = 0;
63642 duk_int_t pc_ldconst = -1;
63643 duk_int_t pc_trycatch = -1;
63644 duk_int_t pc_catch = -1;
63645 duk_int_t pc_finally = -1;
63646
63647 DUK_UNREF(res);
63648
63649 /*
63650 * See the following documentation for discussion:
63651 *
63652 * doc/execution.rst: control flow details
63653 *
63654 * Try, catch, and finally "parts" are Blocks, not Statements, so
63655 * they must always be delimited by curly braces. This is unlike e.g.
63656 * the if statement, which accepts any Statement. This eliminates any
63657 * questions of matching parts of nested try statements. The Block
63658 * parsing is implemented inline here (instead of calling out).
63659 *
63660 * Finally part has a 'let scoped' variable, which requires a few kinks
63661 * here.
63662 */
63663
63664 comp_ctx->curr_func.catch_depth++;
63665
63666 duk__advance(comp_ctx); /* eat 'try' */
63667
63668 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
63669
63670 /* The target for this LDCONST may need output shuffling, but we assume
63671 * that 'pc_ldconst' will be the LDCONST that we can patch later. This
63672 * should be the case because there's no input shuffling. (If there's
63673 * no catch clause, this LDCONST will be replaced with a NOP.)
63674 */
63675 pc_ldconst = duk__get_current_pc(comp_ctx);
63676 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/);
63677
63678 pc_trycatch = duk__get_current_pc(comp_ctx);
63679 duk__emit_invalid(comp_ctx); /* TRYCATCH, cannot emit now (not enough info) */
63680 duk__emit_invalid(comp_ctx); /* jump for 'catch' case */
63681 duk__emit_invalid(comp_ctx); /* jump for 'finally' case or end (if no finally) */
63682
63683 /* try part */
63684 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63685 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
63686 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
63687 duk__emit_extraop_only(comp_ctx,
63688 DUK_EXTRAOP_ENDTRY);
63689
63690 if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
63691 /*
63692 * The catch variable must be updated to reflect the new allocated
63693 * register for the duration of the catch clause. We need to store
63694 * and restore the original value for the varmap entry (if any).
63695 */
63696
63697 /*
63698 * Note: currently register bindings must be fixed for the entire
63699 * function. So, even though the catch variable is in a register
63700 * we know, we must use an explicit environment record and slow path
63701 * accesses to read/write the catch binding to make closures created
63702 * within the catch clause work correctly. This restriction should
63703 * be fixable (at least in common cases) later.
63704 *
63705 * See: test-bug-catch-binding-2.js.
63706 *
63707 * XXX: improve to get fast path access to most catch clauses.
63708 */
63709
63710 duk_hstring *h_var;
63711 duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
63712
63713 DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx)));
63714
63715 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
63716
63717 pc_catch = duk__get_current_pc(comp_ctx);
63718
63719 duk__advance(comp_ctx);
63720 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63721
63722 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
63723 /* Identifier, i.e. don't allow reserved words */
63724 goto syntax_error;
63725 }
63726 h_var = comp_ctx->curr_token.str1;
63727 DUK_ASSERT(h_var != NULL);
63728
63729 duk_push_hstring(ctx, h_var); /* keep in on valstack, use borrowed ref below */
63730
63731 if (comp_ctx->curr_func.is_strict &&
63732 ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
63733 (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) {
63734 DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError"));
63735 goto syntax_error;
63736 }
63737
63738 duk_dup_top(ctx);
63739 rc_varname = duk__getconst(comp_ctx);
63740 DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
63741 (unsigned long) rc_varname, (long) rc_varname));
63742
63743 duk__advance(comp_ctx);
63744 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63745
63746 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63747
63748 DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
63749 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
63750
63751 duk_dup_top(ctx);
63752 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
63753 if (duk_is_undefined(ctx, -1)) {
63754 varmap_value = -2;
63755 } else if (duk_is_null(ctx, -1)) {
63756 varmap_value = -1;
63757 } else {
63758 DUK_ASSERT(duk_is_number(ctx, -1));
63759 varmap_value = duk_get_int(ctx, -1);
63760 DUK_ASSERT(varmap_value >= 0);
63761 }
63762 duk_pop(ctx);
63763
63764#if 0
63765 /* It'd be nice to do something like this - but it doesn't
63766 * work for closures created inside the catch clause.
63767 */
63768 duk_dup_top(ctx);
63769 duk_push_int(ctx, (duk_int_t) (reg_catch + 0));
63770 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
63771#endif
63772 duk_dup_top(ctx);
63773 duk_push_null(ctx);
63774 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
63775
63776 duk__emit_a_bc(comp_ctx,
63777 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
63778 (duk_regconst_t) (reg_catch + 0) /*value*/,
63779 rc_varname /*varname*/);
63780
63781 DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
63782 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
63783
63784 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
63785 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
63786
63787 if (varmap_value == -2) {
63788 /* not present */
63789 duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
63790 } else {
63791 if (varmap_value == -1) {
63792 duk_push_null(ctx);
63793 } else {
63794 DUK_ASSERT(varmap_value >= 0);
63795 duk_push_int(ctx, varmap_value);
63796 }
63797 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
63798 }
63799 /* varname is popped by above code */
63800
63801 DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
63802 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
63803
63804 duk__emit_extraop_only(comp_ctx,
63805 DUK_EXTRAOP_ENDCATCH);
63806
63807 /*
63808 * XXX: for now, indicate that an expensive catch binding
63809 * declarative environment is always needed. If we don't
63810 * need it, we don't need the const_varname either.
63811 */
63812
63813 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
63814
63815 DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx)));
63816 }
63817
63818 if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
63819 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
63820
63821 pc_finally = duk__get_current_pc(comp_ctx);
63822
63823 duk__advance(comp_ctx);
63824
63825 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63826 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
63827 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
63828 duk__emit_extraop_b(comp_ctx,
63829 DUK_EXTRAOP_ENDFIN,
63830 reg_catch); /* rethrow */
63831 }
63832
63833 if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
63834 !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) {
63835 /* must have catch and/or finally */
63836 goto syntax_error;
63837 }
63838
63839 /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch()
63840 * will replace the LDCONST with a NOP. For any actual constant (including
63841 * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname.
63842 */
63843
63844 duk__patch_trycatch(comp_ctx,
63845 pc_ldconst,
63846 pc_trycatch,
63847 reg_catch,
63848 rc_varname,
63849 trycatch_flags);
63850
63851 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
63852 DUK_ASSERT(pc_catch >= 0);
63853 duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch);
63854 }
63855
63856 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
63857 DUK_ASSERT(pc_finally >= 0);
63858 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally);
63859 } else {
63860 /* without finally, the second jump slot is used to jump to end of stmt */
63861 duk__patch_jump_here(comp_ctx, pc_trycatch + 2);
63862 }
63863
63864 comp_ctx->curr_func.catch_depth--;
63865 return;
63866
63867 syntax_error:
63868 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY);
63869}
63870
63871DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63872 duk_int_t pc_trycatch;
63873 duk_int_t pc_finished;
63874 duk_reg_t reg_catch;
63875 duk_small_uint_t trycatch_flags;
63876
63877 if (comp_ctx->curr_func.is_strict) {
63878 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE);
63879 }
63880
63881 comp_ctx->curr_func.catch_depth++;
63882
63883 duk__advance(comp_ctx); /* eat 'with' */
63884
63885 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
63886
63887 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63888 duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch);
63889 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63890
63891 pc_trycatch = duk__get_current_pc(comp_ctx);
63892 trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING;
63893 duk__emit_a_bc(comp_ctx,
63894 DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
63895 (duk_regconst_t) trycatch_flags /*a*/,
63896 (duk_regconst_t) reg_catch /*bc*/);
63897 duk__emit_invalid(comp_ctx); /* catch jump */
63898 duk__emit_invalid(comp_ctx); /* finished jump */
63899
63900 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63901 duk__emit_extraop_only(comp_ctx,
63902 DUK_EXTRAOP_ENDTRY);
63903
63904 pc_finished = duk__get_current_pc(comp_ctx);
63905
63906 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
63907
63908 comp_ctx->curr_func.catch_depth--;
63909}
63910
63911DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) {
63912 /* if a site already exists, nop: max one label site per statement */
63913 if (label_id >= 0) {
63914 return label_id;
63915 }
63916
63917 label_id = comp_ctx->curr_func.label_next++;
63918 DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id));
63919
63920 duk__emit_extraop_bc(comp_ctx,
63921 DUK_EXTRAOP_LABEL,
63922 (duk_regconst_t) label_id);
63923 duk__emit_invalid(comp_ctx);
63924 duk__emit_invalid(comp_ctx);
63925
63926 return label_id;
63927}
63928
63929/* Parse a single statement.
63930 *
63931 * Creates a label site (with an empty label) automatically for iteration
63932 * statements. Also "peels off" any label statements for explicit labels.
63933 */
63934DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
63935 duk_hthread *thr = comp_ctx->thr;
63936 duk_context *ctx = (duk_context *) thr;
63937 duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */
63938 duk_reg_t temp_at_entry;
63939 duk_uarridx_t labels_len_at_entry;
63940 duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */
63941 duk_int_t stmt_id;
63942 duk_small_uint_t stmt_flags = 0;
63943 duk_int_t label_id = -1;
63944 duk_small_uint_t tok;
63945
63946 DUK__RECURSION_INCREASE(comp_ctx, thr);
63947
63948 temp_at_entry = DUK__GETTEMP(comp_ctx);
63949 pc_at_entry = duk__get_current_pc(comp_ctx);
63950 labels_len_at_entry = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.labelnames_idx);
63951 stmt_id = comp_ctx->curr_func.stmt_next++;
63952 dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
63953
63954 DUK_UNREF(stmt_id);
63955
63956 DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, "
63957 "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld",
63958 (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry,
63959 (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue,
63960 (long) comp_ctx->curr_func.catch_depth));
63961
63962 /* The directive prologue flag is cleared by default so that it is
63963 * unset for any recursive statement parsing. It is only "revived"
63964 * if a directive is detected. (We could also make directives only
63965 * allowed if 'allow_source_elem' was true.)
63966 */
63967 comp_ctx->curr_func.in_directive_prologue = 0;
63968
63969 retry_parse:
63970
63971 DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld",
63972 (long) stmt_id, (long) label_id, (long) allow_source_elem,
63973 (long) comp_ctx->curr_func.catch_depth));
63974
63975 /*
63976 * Detect iteration statements; if encountered, establish an
63977 * empty label.
63978 */
63979
63980 tok = comp_ctx->curr_token.t;
63981 if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE ||
63982 tok == DUK_TOK_SWITCH) {
63983 DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label"));
63984
63985 label_id = duk__stmt_label_site(comp_ctx, label_id);
63986 duk__add_label(comp_ctx,
63987 DUK_HTHREAD_STRING_EMPTY_STRING(thr),
63988 pc_at_entry /*pc_label*/,
63989 label_id);
63990 }
63991
63992 /*
63993 * Main switch for statement / source element type.
63994 */
63995
63996 switch (comp_ctx->curr_token.t) {
63997 case DUK_TOK_FUNCTION: {
63998 /*
63999 * Function declaration, function expression, or (non-standard)
64000 * function statement.
64001 *
64002 * The E5 specification only allows function declarations at
64003 * the top level (in "source elements"). An ExpressionStatement
64004 * is explicitly not allowed to begin with a "function" keyword
64005 * (E5 Section 12.4). Hence any non-error semantics for such
64006 * non-top-level statements are non-standard. Duktape semantics
64007 * for function statements are modelled after V8, see
64008 * test-dev-func-decl-outside-top.js.
64009 */
64010
64011#if defined(DUK_USE_NONSTD_FUNC_STMT)
64012 /* Lenient: allow function declarations outside top level in
64013 * non-strict mode but reject them in strict mode.
64014 */
64015 if (allow_source_elem || !comp_ctx->curr_func.is_strict)
64016#else /* DUK_USE_NONSTD_FUNC_STMT */
64017 /* Strict: never allow function declarations outside top level. */
64018 if (allow_source_elem)
64019#endif /* DUK_USE_NONSTD_FUNC_STMT */
64020 {
64021 /* FunctionDeclaration: not strictly a statement but handled as such.
64022 *
64023 * O(depth^2) parse count for inner functions is handled by recording a
64024 * lexer offset on the first compilation pass, so that the function can
64025 * be efficiently skipped on the second pass. This is encapsulated into
64026 * duk__parse_func_like_fnum().
64027 */
64028
64029 duk_int_t fnum;
64030
64031 DUK_DDD(DUK_DDDPRINT("function declaration statement"));
64032
64033 duk__advance(comp_ctx); /* eat 'function' */
64034 fnum = duk__parse_func_like_fnum(comp_ctx, 1 /*is_decl*/, 0 /*is_setget*/);
64035
64036 if (comp_ctx->curr_func.in_scanning) {
64037 duk_uarridx_t n;
64038 duk_hstring *h_funcname;
64039
64040 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, fnum * 3);
64041 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); /* -> [ ... func name ] */
64042 h_funcname = duk_get_hstring(ctx, -1);
64043 DUK_ASSERT(h_funcname != NULL);
64044
64045 DUK_DDD(DUK_DDDPRINT("register function declaration %!O in pass 1, fnum %ld",
64046 (duk_heaphdr *) h_funcname, (long) fnum));
64047 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
64048 duk_push_hstring(ctx, h_funcname);
64049 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
64050 duk_push_int(ctx, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
64051 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
64052
64053 duk_pop_n(ctx, 2);
64054 }
64055
64056 /* no statement value (unlike function expression) */
64057 stmt_flags = 0;
64058 break;
64059 } else {
64060 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED);
64061 }
64062 break;
64063 }
64064 case DUK_TOK_LCURLY: {
64065 DUK_DDD(DUK_DDDPRINT("block statement"));
64066 duk__advance(comp_ctx);
64067 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
64068 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
64069 if (label_id >= 0) {
64070 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
64071 }
64072 stmt_flags = 0;
64073 break;
64074 }
64075 case DUK_TOK_CONST: {
64076 DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
64077 duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/);
64078 stmt_flags = DUK__HAS_TERM;
64079 break;
64080 }
64081 case DUK_TOK_VAR: {
64082 DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
64083 duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/);
64084 stmt_flags = DUK__HAS_TERM;
64085 break;
64086 }
64087 case DUK_TOK_SEMICOLON: {
64088 /* empty statement with an explicit semicolon */
64089 DUK_DDD(DUK_DDDPRINT("empty statement"));
64090 stmt_flags = DUK__HAS_TERM;
64091 break;
64092 }
64093 case DUK_TOK_IF: {
64094 DUK_DDD(DUK_DDDPRINT("if statement"));
64095 duk__parse_if_stmt(comp_ctx, res);
64096 if (label_id >= 0) {
64097 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
64098 }
64099 stmt_flags = 0;
64100 break;
64101 }
64102 case DUK_TOK_DO: {
64103 /*
64104 * Do-while statement is mostly trivial, but there is special
64105 * handling for automatic semicolon handling (triggered by the
64106 * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
64107 *
64108 * https://bugs.ecmascript.org/show_bug.cgi?id=8
64109 *
64110 * See doc/compiler.rst for details.
64111 */
64112 DUK_DDD(DUK_DDDPRINT("do statement"));
64113 DUK_ASSERT(label_id >= 0);
64114 duk__update_label_flags(comp_ctx,
64115 label_id,
64116 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
64117 duk__parse_do_stmt(comp_ctx, res, pc_at_entry);
64118 stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
64119 break;
64120 }
64121 case DUK_TOK_WHILE: {
64122 DUK_DDD(DUK_DDDPRINT("while statement"));
64123 DUK_ASSERT(label_id >= 0);
64124 duk__update_label_flags(comp_ctx,
64125 label_id,
64126 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
64127 duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
64128 stmt_flags = 0;
64129 break;
64130 }
64131 case DUK_TOK_FOR: {
64132 /*
64133 * For/for-in statement is complicated to parse because
64134 * determining the statement type (three-part for vs. a
64135 * for-in) requires potential backtracking.
64136 *
64137 * See the helper for the messy stuff.
64138 */
64139 DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
64140 DUK_ASSERT(label_id >= 0);
64141 duk__update_label_flags(comp_ctx,
64142 label_id,
64143 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
64144 duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
64145 stmt_flags = 0;
64146 break;
64147 }
64148 case DUK_TOK_CONTINUE:
64149 case DUK_TOK_BREAK: {
64150 DUK_DDD(DUK_DDDPRINT("break/continue statement"));
64151 duk__parse_break_or_continue_stmt(comp_ctx, res);
64152 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
64153 break;
64154 }
64155 case DUK_TOK_RETURN: {
64156 DUK_DDD(DUK_DDDPRINT("return statement"));
64157 duk__parse_return_stmt(comp_ctx, res);
64158 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
64159 break;
64160 }
64161 case DUK_TOK_WITH: {
64162 DUK_DDD(DUK_DDDPRINT("with statement"));
64163 comp_ctx->curr_func.with_depth++;
64164 duk__parse_with_stmt(comp_ctx, res);
64165 if (label_id >= 0) {
64166 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
64167 }
64168 comp_ctx->curr_func.with_depth--;
64169 stmt_flags = 0;
64170 break;
64171 }
64172 case DUK_TOK_SWITCH: {
64173 /*
64174 * The switch statement is pretty messy to compile.
64175 * See the helper for details.
64176 */
64177 DUK_DDD(DUK_DDDPRINT("switch statement"));
64178 DUK_ASSERT(label_id >= 0);
64179 duk__update_label_flags(comp_ctx,
64180 label_id,
64181 DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */
64182 duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
64183 stmt_flags = 0;
64184 break;
64185 }
64186 case DUK_TOK_THROW: {
64187 DUK_DDD(DUK_DDDPRINT("throw statement"));
64188 duk__parse_throw_stmt(comp_ctx, res);
64189 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
64190 break;
64191 }
64192 case DUK_TOK_TRY: {
64193 DUK_DDD(DUK_DDDPRINT("try statement"));
64194 duk__parse_try_stmt(comp_ctx, res);
64195 stmt_flags = 0;
64196 break;
64197 }
64198 case DUK_TOK_DEBUGGER: {
64199 duk__advance(comp_ctx);
64200#if defined(DUK_USE_DEBUGGER_SUPPORT)
64201 DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
64202 duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_DEBUGGER);
64203#else
64204 DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
64205#endif
64206 stmt_flags = DUK__HAS_TERM;
64207 break;
64208 }
64209 default: {
64210 /*
64211 * Else, must be one of:
64212 * - ExpressionStatement, possibly a directive (String)
64213 * - LabelledStatement (Identifier followed by ':')
64214 *
64215 * Expressions beginning with 'function' keyword are covered by a case
64216 * above (such expressions are not allowed in standard E5 anyway).
64217 * Also expressions starting with '{' are interpreted as block
64218 * statements. See E5 Section 12.4.
64219 *
64220 * Directive detection is tricky; see E5 Section 14.1 on directive
64221 * prologue. A directive is an expression statement with a single
64222 * string literal and an explicit or automatic semicolon. Escape
64223 * characters are significant and no parens etc are allowed:
64224 *
64225 * 'use strict'; // valid 'use strict' directive
64226 * 'use\u0020strict'; // valid directive, not a 'use strict' directive
64227 * ('use strict'); // not a valid directive
64228 *
64229 * The expression is determined to consist of a single string literal
64230 * based on duk__expr_nud() and duk__expr_led() call counts. The string literal
64231 * of a 'use strict' directive is determined to lack any escapes based
64232 * num_escapes count from the lexer. Note that other directives may be
64233 * allowed to contain escapes, so a directive with escapes does not
64234 * terminate a directive prologue.
64235 *
64236 * We rely on the fact that the expression parser will not emit any
64237 * code for a single token expression. However, it will generate an
64238 * intermediate value which we will then successfully ignore.
64239 *
64240 * A similar approach is used for labels.
64241 */
64242
64243 duk_bool_t single_token;
64244
64245 DUK_DDD(DUK_DDDPRINT("expression statement"));
64246 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
64247
64248 single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */
64249 comp_ctx->curr_func.led_count == 0); /* no operators */
64250
64251 if (single_token &&
64252 comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
64253 comp_ctx->curr_token.t == DUK_TOK_COLON) {
64254 /*
64255 * Detected label
64256 */
64257
64258 duk_hstring *h_lab;
64259
64260 /* expected ival */
64261 DUK_ASSERT(res->t == DUK_IVAL_VAR);
64262 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
64263 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
64264 h_lab = comp_ctx->prev_token.str1;
64265 DUK_ASSERT(h_lab != NULL);
64266
64267 DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
64268 (duk_heaphdr *) h_lab));
64269
64270 duk__advance(comp_ctx); /* eat colon */
64271
64272 label_id = duk__stmt_label_site(comp_ctx, label_id);
64273
64274 duk__add_label(comp_ctx,
64275 h_lab,
64276 pc_at_entry /*pc_label*/,
64277 label_id);
64278
64279 /* a statement following a label cannot be a source element
64280 * (a function declaration).
64281 */
64282 allow_source_elem = 0;
64283
64284 DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
64285 goto retry_parse;
64286 }
64287
64288 stmt_flags = 0;
64289
64290 if (dir_prol_at_entry && /* still in prologue */
64291 single_token && /* single string token */
64292 comp_ctx->prev_token.t == DUK_TOK_STRING) {
64293 /*
64294 * Detected a directive
64295 */
64296 duk_hstring *h_dir;
64297
64298 /* expected ival */
64299 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
64300 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
64301 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
64302 h_dir = comp_ctx->prev_token.str1;
64303 DUK_ASSERT(h_dir != NULL);
64304
64305 DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir));
64306
64307 stmt_flags |= DUK__STILL_PROLOGUE;
64308
64309 /* Note: escaped characters differentiate directives */
64310
64311 if (comp_ctx->prev_token.num_escapes > 0) {
64312 DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive "
64313 "but we ignore such directives"));
64314 } else {
64315 /*
64316 * The length comparisons are present to handle
64317 * strings like "use strict\u0000foo" as required.
64318 */
64319
64320 if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
64321 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict", 10) == 0) {
64322#if defined(DUK_USE_STRICT_DECL)
64323 DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld",
64324 (long) comp_ctx->curr_func.is_strict, (long) 1));
64325 comp_ctx->curr_func.is_strict = 1;
64326#else
64327 DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
64328#endif
64329 } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 &&
64330 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail", 14) == 0) {
64331 DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld",
64332 (long) comp_ctx->curr_func.is_notail, (long) 1));
64333 comp_ctx->curr_func.is_notail = 1;
64334 } else {
64335 DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
64336 "directive prologue", (duk_hobject *) h_dir));
64337 }
64338 }
64339 } else {
64340 DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
64341 "prologue terminated if still active"));
64342 }
64343
64344 stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
64345 }
64346 } /* end switch (tok) */
64347
64348 /*
64349 * Statement value handling.
64350 *
64351 * Global code and eval code has an implicit return value
64352 * which comes from the last statement with a value
64353 * (technically a non-"empty" continuation, which is
64354 * different from an empty statement).
64355 *
64356 * Since we don't know whether a later statement will
64357 * override the value of the current statement, we need
64358 * to coerce the statement value to a register allocated
64359 * for implicit return values. In other cases we need
64360 * to coerce the statement value to a plain value to get
64361 * any side effects out (consider e.g. "foo.bar;").
64362 */
64363
64364 /* XXX: what about statements which leave a half-cooked value in 'res'
64365 * but have no stmt value? Any such statements?
64366 */
64367
64368 if (stmt_flags & DUK__HAS_VAL) {
64369 duk_reg_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
64370 if (reg_stmt_value >= 0) {
64371 duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
64372 } else {
64373 duk__ivalue_toplain_ignore(comp_ctx, res);
64374 }
64375 } else {
64376 ;
64377 }
64378
64379 /*
64380 * Statement terminator check, including automatic semicolon
64381 * handling. After this step, 'curr_tok' should be the first
64382 * token after a possible statement terminator.
64383 */
64384
64385 if (stmt_flags & DUK__HAS_TERM) {
64386 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) {
64387 DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement"));
64388 duk__advance(comp_ctx);
64389 } else {
64390 if (comp_ctx->curr_token.allow_auto_semi) {
64391 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement"));
64392 } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) {
64393 /* XXX: make this lenience dependent on flags or strictness? */
64394 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
64395 "even though no lineterm present before next token)"));
64396 } else {
64397 DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT);
64398 }
64399 }
64400 } else {
64401 DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
64402 }
64403
64404 /*
64405 * Directive prologue tracking.
64406 */
64407
64408 if (stmt_flags & DUK__STILL_PROLOGUE) {
64409 DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue"));
64410 comp_ctx->curr_func.in_directive_prologue = 1;
64411 }
64412
64413 /*
64414 * Cleanups (all statement parsing flows through here).
64415 *
64416 * Pop label site and reset labels. Reset 'next temp' to value at
64417 * entry to reuse temps.
64418 */
64419
64420 if (label_id >= 0) {
64421 duk__emit_extraop_bc(comp_ctx,
64422 DUK_EXTRAOP_ENDLABEL,
64423 (duk_regconst_t) label_id);
64424 }
64425
64426 DUK__SETTEMP(comp_ctx, temp_at_entry);
64427
64428 duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
64429
64430 /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
64431
64432 DUK__RECURSION_DECREASE(comp_ctx, thr);
64433}
64434
64435#undef DUK__HAS_VAL
64436#undef DUK__HAS_TERM
64437#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
64438
64439/*
64440 * Parse a statement list.
64441 *
64442 * Handles automatic semicolon insertion and implicit return value.
64443 *
64444 * Upon entry, 'curr_tok' should contain the first token of the first
64445 * statement (parsed in the "allow regexp literal" mode). Upon exit,
64446 * 'curr_tok' contains the token following the statement list terminator
64447 * (EOF or closing brace).
64448 */
64449
64450DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) {
64451 duk_hthread *thr = comp_ctx->thr;
64452 duk_context *ctx = (duk_context *) thr;
64453 duk_ivalue res_alloc;
64454 duk_ivalue *res = &res_alloc;
64455
64456 /* Setup state. Initial ivalue is 'undefined'. */
64457
64458 duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
64459
64460 /* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
64461 * intermediate values suffice for parsing of each function. Nesting is needed
64462 * for nested functions (which may occur inside expressions).
64463 */
64464
64465 DUK_MEMZERO(&res_alloc, sizeof(res_alloc));
64466 res->t = DUK_IVAL_PLAIN;
64467 res->x1.t = DUK_ISPEC_VALUE;
64468 res->x1.valstack_idx = duk_get_top(ctx);
64469 res->x2.valstack_idx = res->x1.valstack_idx + 1;
64470 duk_push_undefined(ctx);
64471 duk_push_undefined(ctx);
64472
64473 /* Parse statements until a closing token (EOF or '}') is found. */
64474
64475 for (;;) {
64476 /* Check whether statement list ends. */
64477
64478 if (expect_eof) {
64479 if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
64480 break;
64481 }
64482 } else {
64483 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
64484 break;
64485 }
64486 }
64487
64488 /* Check statement type based on the first token type.
64489 *
64490 * Note: expression parsing helpers expect 'curr_tok' to
64491 * contain the first token of the expression upon entry.
64492 */
64493
64494 DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t));
64495
64496 duk__parse_stmt(comp_ctx, res, allow_source_elem);
64497 }
64498
64499 duk__advance(comp_ctx);
64500
64501 /* Tear down state. */
64502
64503 duk_pop_2(ctx);
64504}
64505
64506/*
64507 * Declaration binding instantiation conceptually happens when calling a
64508 * function; for us it essentially means that function prologue. The
64509 * conceptual process is described in E5 Section 10.5.
64510 *
64511 * We need to keep track of all encountered identifiers to (1) create an
64512 * identifier-to-register map ("varmap"); and (2) detect duplicate
64513 * declarations. Identifiers which are not bound to registers still need
64514 * to be tracked for detecting duplicates. Currently such identifiers
64515 * are put into the varmap with a 'null' value, which is later cleaned up.
64516 *
64517 * To support functions with a large number of variable and function
64518 * declarations, registers are not allocated beyond a certain limit;
64519 * after that limit, variables and functions need slow path access.
64520 * Arguments are currently always register bound, which imposes a hard
64521 * (and relatively small) argument count limit.
64522 *
64523 * Some bindings in E5 are not configurable (= deletable) and almost all
64524 * are mutable (writable). Exceptions are:
64525 *
64526 * - The 'arguments' binding, established only if no shadowing argument
64527 * or function declaration exists. We handle 'arguments' creation
64528 * and binding through an explicit slow path environment record.
64529 *
64530 * - The "name" binding for a named function expression. This is also
64531 * handled through an explicit slow path environment record.
64532 */
64533
64534/* XXX: add support for variables to not be register bound always, to
64535 * handle cases with a very large number of variables?
64536 */
64537
64538DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg) {
64539 duk_hthread *thr = comp_ctx->thr;
64540 duk_context *ctx = (duk_context *) thr;
64541 duk_hstring *h_name;
64542 duk_bool_t configurable_bindings;
64543 duk_uarridx_t num_args;
64544 duk_uarridx_t num_decls;
64545 duk_regconst_t rc_name;
64546 duk_small_uint_t declvar_flags;
64547 duk_uarridx_t i;
64548#ifdef DUK_USE_ASSERTIONS
64549 duk_idx_t entry_top;
64550#endif
64551
64552#ifdef DUK_USE_ASSERTIONS
64553 entry_top = duk_get_top(ctx);
64554#endif
64555
64556 /*
64557 * Preliminaries
64558 */
64559
64560 configurable_bindings = comp_ctx->curr_func.is_eval;
64561 DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings));
64562
64563 /* varmap is already in comp_ctx->curr_func.varmap_idx */
64564
64565 /*
64566 * Function formal arguments, always bound to registers
64567 * (there's no support for shuffling them now).
64568 */
64569
64570 num_args = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
64571 DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
64572 /* XXX: check num_args */
64573
64574 for (i = 0; i < num_args; i++) {
64575 duk_get_prop_index(ctx, comp_ctx->curr_func.argnames_idx, i);
64576 h_name = duk_get_hstring(ctx, -1);
64577 DUK_ASSERT(h_name != NULL);
64578
64579 if (comp_ctx->curr_func.is_strict) {
64580 if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
64581 DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
64582 goto error_argname;
64583 }
64584 duk_dup_top(ctx);
64585 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
64586 DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
64587 goto error_argname;
64588 }
64589
64590 /* Ensure argument name is not a reserved word in current
64591 * (final) strictness. Formal argument parsing may not
64592 * catch reserved names if strictness changes during
64593 * parsing.
64594 *
64595 * We only need to do this in strict mode because non-strict
64596 * keyword are always detected in formal argument parsing.
64597 */
64598
64599 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
64600 goto error_argname;
64601 }
64602 }
64603
64604 /* overwrite any previous binding of the same name; the effect is
64605 * that last argument of a certain name wins.
64606 */
64607
64608 /* only functions can have arguments */
64609 DUK_ASSERT(comp_ctx->curr_func.is_function);
64610 duk_push_uarridx(ctx, i); /* -> [ ... name index ] */
64611 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
64612
64613 /* no code needs to be emitted, the regs already have values */
64614 }
64615
64616 /* use temp_next for tracking register allocations */
64617 DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_reg_t) num_args);
64618
64619 /*
64620 * After arguments, allocate special registers (like shuffling temps)
64621 */
64622
64623 if (out_stmt_value_reg) {
64624 *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
64625 }
64626 if (comp_ctx->curr_func.needs_shuffle) {
64627 duk_reg_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
64628 comp_ctx->curr_func.shuffle1 = shuffle_base;
64629 comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
64630 comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
64631 DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld",
64632 (long) comp_ctx->curr_func.shuffle1,
64633 (long) comp_ctx->curr_func.shuffle2,
64634 (long) comp_ctx->curr_func.shuffle3));
64635 }
64636 if (comp_ctx->curr_func.temp_next > 0x100) {
64637 DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx->curr_func.temp_next));
64638 goto error_outofregs;
64639 }
64640
64641 /*
64642 * Function declarations
64643 */
64644
64645 num_decls = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
64646 DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
64647 (long) num_decls,
64648 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.decls_idx)));
64649 for (i = 0; i < num_decls; i += 2) {
64650 duk_int_t decl_type;
64651 duk_int_t fnum;
64652
64653 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
64654 decl_type = duk_to_int(ctx, -1);
64655 fnum = decl_type >> 8; /* XXX: macros */
64656 decl_type = decl_type & 0xff;
64657 duk_pop(ctx);
64658
64659 if (decl_type != DUK_DECL_TYPE_FUNC) {
64660 continue;
64661 }
64662
64663 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
64664
64665 /* XXX: spilling */
64666 if (comp_ctx->curr_func.is_function) {
64667 duk_reg_t reg_bind;
64668 duk_dup_top(ctx);
64669 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
64670 /* shadowed; update value */
64671 duk_dup_top(ctx);
64672 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
64673 reg_bind = duk_to_int(ctx, -1); /* [ ... name reg_bind ] */
64674 duk__emit_a_bc(comp_ctx,
64675 DUK_OP_CLOSURE,
64676 (duk_regconst_t) reg_bind,
64677 (duk_regconst_t) fnum);
64678 } else {
64679 /* function: always register bound */
64680 reg_bind = DUK__ALLOCTEMP(comp_ctx);
64681 duk__emit_a_bc(comp_ctx,
64682 DUK_OP_CLOSURE,
64683 (duk_regconst_t) reg_bind,
64684 (duk_regconst_t) fnum);
64685 duk_push_int(ctx, (duk_int_t) reg_bind);
64686 }
64687 } else {
64688 /* Function declaration for global/eval code is emitted even
64689 * for duplicates, because of E5 Section 10.5, step 5.e of
64690 * E5.1 (special behavior for variable bound to global object).
64691 *
64692 * DECLVAR will not re-declare a variable as such, but will
64693 * update the binding value.
64694 */
64695
64696 duk_reg_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
64697 duk_dup_top(ctx);
64698 rc_name = duk__getconst(comp_ctx);
64699 duk_push_null(ctx);
64700
64701 duk__emit_a_bc(comp_ctx,
64702 DUK_OP_CLOSURE,
64703 (duk_regconst_t) reg_temp,
64704 (duk_regconst_t) fnum);
64705
64706 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
64707 DUK_PROPDESC_FLAG_ENUMERABLE |
64708 DUK_BC_DECLVAR_FLAG_FUNC_DECL;
64709
64710 if (configurable_bindings) {
64711 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
64712 }
64713
64714 duk__emit_a_b_c(comp_ctx,
64715 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
64716 (duk_regconst_t) declvar_flags /*flags*/,
64717 rc_name /*name*/,
64718 (duk_regconst_t) reg_temp /*value*/);
64719
64720 DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
64721 }
64722
64723 DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
64724 (duk_tval *) duk_get_tval(ctx, -2),
64725 (duk_tval *) duk_get_tval(ctx, -1)));
64726
64727 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
64728 }
64729
64730 /*
64731 * 'arguments' binding is special; if a shadowing argument or
64732 * function declaration exists, an arguments object will
64733 * definitely not be needed, regardless of whether the identifier
64734 * 'arguments' is referenced inside the function body.
64735 */
64736
64737 if (duk_has_prop_stridx(ctx, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
64738 DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
64739 "-> arguments object creation can be skipped"));
64740 comp_ctx->curr_func.is_arguments_shadowed = 1;
64741 }
64742
64743 /*
64744 * Variable declarations.
64745 *
64746 * Unlike function declarations, variable declaration values don't get
64747 * assigned on entry. If a binding of the same name already exists, just
64748 * ignore it silently.
64749 */
64750
64751 for (i = 0; i < num_decls; i += 2) {
64752 duk_int_t decl_type;
64753
64754 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
64755 decl_type = duk_to_int(ctx, -1);
64756 decl_type = decl_type & 0xff;
64757 duk_pop(ctx);
64758
64759 if (decl_type != DUK_DECL_TYPE_VAR) {
64760 continue;
64761 }
64762
64763 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
64764
64765 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
64766 /* shadowed, ignore */
64767 } else {
64768 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
64769 h_name = duk_get_hstring(ctx, -1);
64770 DUK_ASSERT(h_name != NULL);
64771
64772 if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
64773 !comp_ctx->curr_func.is_arguments_shadowed) {
64774 /* E5 Section steps 7-8 */
64775 DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
64776 "but appears as a variable declaration -> treat as "
64777 "a no-op for variable declaration purposes"));
64778 duk_pop(ctx);
64779 continue;
64780 }
64781
64782 /* XXX: spilling */
64783 if (comp_ctx->curr_func.is_function) {
64784 duk_reg_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
64785 /* no need to init reg, it will be undefined on entry */
64786 duk_push_int(ctx, (duk_int_t) reg_bind);
64787 } else {
64788 duk_dup_top(ctx);
64789 rc_name = duk__getconst(comp_ctx);
64790 duk_push_null(ctx);
64791
64792 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
64793 DUK_PROPDESC_FLAG_ENUMERABLE |
64794 DUK_BC_DECLVAR_FLAG_UNDEF_VALUE;
64795 if (configurable_bindings) {
64796 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
64797 }
64798
64799 duk__emit_a_b_c(comp_ctx,
64800 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
64801 (duk_regconst_t) declvar_flags /*flags*/,
64802 rc_name /*name*/,
64803 (duk_regconst_t) 0 /*value*/);
64804 }
64805
64806 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
64807 }
64808 }
64809
64810 /*
64811 * Wrap up
64812 */
64813
64814 DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
64815 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx),
64816 (long) comp_ctx->curr_func.is_arguments_shadowed));
64817
64818 DUK_ASSERT_TOP(ctx, entry_top);
64819 return;
64820
64821 error_outofregs:
64822 DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT);
64823 DUK_UNREACHABLE();
64824 return;
64825
64826 error_argname:
64827 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME);
64828 DUK_UNREACHABLE();
64829 return;
64830}
64831
64832/*
64833 * Parse a function-body-like expression (FunctionBody or Program
64834 * in E5 grammar) using a two-pass parse. The productions appear
64835 * in the following contexts:
64836 *
64837 * - function expression
64838 * - function statement
64839 * - function declaration
64840 * - getter in object literal
64841 * - setter in object literal
64842 * - global code
64843 * - eval code
64844 * - Function constructor body
64845 *
64846 * This function only parses the statement list of the body; the argument
64847 * list and possible function name must be initialized by the caller.
64848 * For instance, for Function constructor, the argument names are originally
64849 * on the value stack. The parsing of statements ends either at an EOF or
64850 * a closing brace; this is controlled by an input flag.
64851 *
64852 * Note that there are many differences affecting parsing and even code
64853 * generation:
64854 *
64855 * - Global and eval code have an implicit return value generated
64856 * by the last statement; function code does not
64857 *
64858 * - Global code, eval code, and Function constructor body end in
64859 * an EOF, other bodies in a closing brace ('}')
64860 *
64861 * Upon entry, 'curr_tok' is ignored and the function will pull in the
64862 * first token on its own. Upon exit, 'curr_tok' is the terminating
64863 * token (EOF or closing brace).
64864 */
64865
64866DUK_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) {
64867 duk_compiler_func *func;
64868 duk_hthread *thr;
64869 duk_context *ctx;
64870 duk_reg_t reg_stmt_value = -1;
64871 duk_lexer_point lex_pt;
64872 duk_reg_t temp_first;
64873 duk_small_int_t compile_round = 1;
64874
64875 DUK_ASSERT(comp_ctx != NULL);
64876
64877 thr = comp_ctx->thr;
64878 ctx = (duk_context *) thr;
64879 DUK_ASSERT(thr != NULL);
64880
64881 func = &comp_ctx->curr_func;
64882 DUK_ASSERT(func != NULL);
64883
64884 DUK__RECURSION_INCREASE(comp_ctx, thr);
64885
64886 duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
64887
64888 /*
64889 * Store lexer position for a later rewind
64890 */
64891
64892 DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
64893
64894 /*
64895 * Program code (global and eval code) has an implicit return value
64896 * from the last statement value (e.g. eval("1; 2+3;") returns 3).
64897 * This is not the case with functions. If implicit statement return
64898 * value is requested, all statements are coerced to a register
64899 * allocated here, and used in the implicit return statement below.
64900 */
64901
64902 /* XXX: this is pointless here because pass 1 is throw-away */
64903 if (implicit_return_value) {
64904 reg_stmt_value = DUK__ALLOCTEMP(comp_ctx);
64905
64906 /* If an implicit return value is needed by caller, it must be
64907 * initialized to 'undefined' because we don't know whether any
64908 * non-empty (where "empty" is a continuation type, and different
64909 * from an empty statement) statements will be executed.
64910 *
64911 * However, since 1st pass is a throwaway one, no need to emit
64912 * it here.
64913 */
64914#if 0
64915 duk__emit_extraop_bc(comp_ctx,
64916 DUK_EXTRAOP_LDUNDEF,
64917 0);
64918#endif
64919 }
64920
64921 /*
64922 * First pass.
64923 *
64924 * Gather variable/function declarations needed for second pass.
64925 * Code generated is dummy and discarded.
64926 */
64927
64928 func->in_directive_prologue = 1;
64929 func->in_scanning = 1;
64930 func->may_direct_eval = 0;
64931 func->id_access_arguments = 0;
64932 func->id_access_slow = 0;
64933 func->reg_stmt_value = reg_stmt_value;
64934#if defined(DUK_USE_DEBUGGER_SUPPORT)
64935 func->min_line = DUK_INT_MAX;
64936 func->max_line = 0;
64937#endif
64938
64939 /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */
64940 if (expect_token >= 0) {
64941 /* Eating a left curly; regexp mode is allowed by left curly
64942 * based on duk__token_lbp[] automatically.
64943 */
64944 DUK_ASSERT(expect_token == DUK_TOK_LCURLY);
64945 duk__update_lineinfo_currtoken(comp_ctx);
64946 duk__advance_expect(comp_ctx, expect_token);
64947 } else {
64948 /* Need to set curr_token.t because lexing regexp mode depends on current
64949 * token type. Zero value causes "allow regexp" mode.
64950 */
64951 comp_ctx->curr_token.t = 0;
64952 duk__advance(comp_ctx);
64953 }
64954
64955 DUK_DDD(DUK_DDDPRINT("begin 1st pass"));
64956 duk__parse_stmts(comp_ctx,
64957 1, /* allow source elements */
64958 expect_eof); /* expect EOF instead of } */
64959 DUK_DDD(DUK_DDDPRINT("end 1st pass"));
64960
64961 /*
64962 * Second (and possibly third) pass.
64963 *
64964 * Generate actual code. In most cases the need for shuffle
64965 * registers is detected during pass 1, but in some corner cases
64966 * we'll only detect it during pass 2 and a third pass is then
64967 * needed (see GH-115).
64968 */
64969
64970 for (;;) {
64971 duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle;
64972 compile_round++;
64973
64974 /*
64975 * Rewind lexer.
64976 *
64977 * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
64978 * literal" mode with current strictness.
64979 *
64980 * curr_token line number info should be initialized for pass 2 before
64981 * generating prologue, to ensure prologue bytecode gets nice line numbers.
64982 */
64983
64984 DUK_DDD(DUK_DDDPRINT("rewind lexer"));
64985 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
64986 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
64987 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
64988 duk__advance(comp_ctx);
64989
64990 /*
64991 * Reset function state and perform register allocation, which creates
64992 * 'varmap' for second pass. Function prologue for variable declarations,
64993 * binding value initializations etc is emitted as a by-product.
64994 *
64995 * Strict mode restrictions for duplicate and invalid argument
64996 * names are checked here now that we know whether the function
64997 * is actually strict. See: test-dev-strict-mode-boundary.js.
64998 *
64999 * Inner functions are compiled during pass 1 and are not reset.
65000 */
65001
65002 duk__reset_func_for_pass2(comp_ctx);
65003 func->in_directive_prologue = 1;
65004 func->in_scanning = 0;
65005
65006 /* must be able to emit code, alloc consts, etc. */
65007
65008 duk__init_varmap_and_prologue_for_pass2(comp_ctx,
65009 (implicit_return_value ? &reg_stmt_value : NULL));
65010 func->reg_stmt_value = reg_stmt_value;
65011
65012 temp_first = DUK__GETTEMP(comp_ctx);
65013
65014 func->temp_first = temp_first;
65015 func->temp_next = temp_first;
65016 func->stmt_next = 0;
65017 func->label_next = 0;
65018
65019 /* XXX: init or assert catch depth etc -- all values */
65020 func->id_access_arguments = 0;
65021 func->id_access_slow = 0;
65022
65023 /*
65024 * Check function name validity now that we know strictness.
65025 * This only applies to function declarations and expressions,
65026 * not setter/getter name.
65027 *
65028 * See: test-dev-strict-mode-boundary.js
65029 */
65030
65031 if (func->is_function && !func->is_setget && func->h_name != NULL) {
65032 if (func->is_strict) {
65033 if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) {
65034 DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode"));
65035 goto error_funcname;
65036 }
65037 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
65038 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode"));
65039 goto error_funcname;
65040 }
65041 } else {
65042 if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) &&
65043 !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
65044 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode"));
65045 goto error_funcname;
65046 }
65047 }
65048 }
65049
65050 /*
65051 * Second pass parsing.
65052 */
65053
65054 if (implicit_return_value) {
65055 /* Default implicit return value. */
65056 duk__emit_extraop_bc(comp_ctx,
65057 DUK_EXTRAOP_LDUNDEF,
65058 0);
65059 }
65060
65061 DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
65062 duk__parse_stmts(comp_ctx,
65063 1, /* allow source elements */
65064 expect_eof); /* expect EOF instead of } */
65065 DUK_DDD(DUK_DDDPRINT("end 2nd pass"));
65066
65067 duk__update_lineinfo_currtoken(comp_ctx);
65068
65069 if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) {
65070 /* Shuffle decision not changed. */
65071 break;
65072 }
65073 if (compile_round >= 3) {
65074 /* Should never happen but avoid infinite loop just in case. */
65075 DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
65076 DUK_ERROR_INTERNAL_DEFMSG(thr);
65077 }
65078 DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
65079 }
65080
65081 /*
65082 * Emit a final RETURN.
65083 *
65084 * It would be nice to avoid emitting an unnecessary "return" opcode
65085 * if the current PC is not reachable. However, this cannot be reliably
65086 * detected; even if the previous instruction is an unconditional jump,
65087 * there may be a previous jump which jumps to current PC (which is the
65088 * case for iteration and conditional statements, for instance).
65089 */
65090
65091 /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
65092 * we could avoid the last RETURN if we could ensure there is no way to get here
65093 * (directly or via a jump)
65094 */
65095
65096 DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
65097 if (reg_stmt_value >= 0) {
65098 duk__emit_a_b(comp_ctx,
65099 DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
65100 (duk_regconst_t) DUK_BC_RETURN_FLAG_HAVE_RETVAL /*flags*/,
65101 (duk_regconst_t) reg_stmt_value /*reg*/);
65102 } else {
65103 duk__emit_a_b(comp_ctx,
65104 DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
65105 (duk_regconst_t) 0 /*flags*/,
65106 (duk_regconst_t) 0 /*reg(ignored)*/);
65107 }
65108
65109 /*
65110 * Peephole optimize JUMP chains.
65111 */
65112
65113 duk__peephole_optimize_bytecode(comp_ctx);
65114
65115 /*
65116 * comp_ctx->curr_func is now ready to be converted into an actual
65117 * function template.
65118 */
65119
65120 DUK__RECURSION_DECREASE(comp_ctx, thr);
65121 return;
65122
65123 error_funcname:
65124 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME);
65125}
65126
65127/*
65128 * Parse a function-like expression:
65129 *
65130 * - function expression
65131 * - function declaration
65132 * - function statement (non-standard)
65133 * - setter/getter
65134 *
65135 * Adds the function to comp_ctx->curr_func function table and returns the
65136 * function number.
65137 *
65138 * On entry, curr_token points to:
65139 *
65140 * - the token after 'function' for function expression/declaration/statement
65141 * - the token after 'set' or 'get' for setter/getter
65142 */
65143
65144/* Parse formals. */
65145DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
65146 duk_hthread *thr = comp_ctx->thr;
65147 duk_context *ctx = (duk_context *) thr;
65148 duk_bool_t first = 1;
65149 duk_uarridx_t n;
65150
65151 for (;;) {
65152 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
65153 break;
65154 }
65155
65156 if (first) {
65157 /* no comma */
65158 first = 0;
65159 } else {
65160 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
65161 }
65162
65163 /* Note: when parsing a formal list in non-strict context, e.g.
65164 * "implements" is parsed as an identifier. When the function is
65165 * later detected to be strict, the argument list must be rechecked
65166 * against a larger set of reserved words (that of strict mode).
65167 * This is handled by duk__parse_func_body(). Here we recognize
65168 * whatever tokens are considered reserved in current strictness
65169 * (which is not always enough).
65170 */
65171
65172 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
65173 DUK_ERROR_SYNTAX(thr, "expected identifier");
65174 }
65175 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
65176 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
65177 DUK_DDD(DUK_DDDPRINT("formal argument: %!O",
65178 (duk_heaphdr *) comp_ctx->curr_token.str1));
65179
65180 /* XXX: append primitive */
65181 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
65182 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
65183 duk_put_prop_index(ctx, comp_ctx->curr_func.argnames_idx, n);
65184
65185 duk__advance(comp_ctx); /* eat identifier */
65186 }
65187}
65188
65189/* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
65190 * correctly set up. Assumes that curr_token is just after 'function' (or
65191 * 'set'/'get' etc).
65192 */
65193DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
65194 duk_hthread *thr = comp_ctx->thr;
65195 duk_context *ctx = (duk_context *) thr;
65196
65197 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
65198 DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
65199 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
65200 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
65201 DUK_ASSERT(comp_ctx->curr_func.is_setget == is_setget);
65202 DUK_ASSERT(comp_ctx->curr_func.is_decl == is_decl);
65203
65204 duk__update_lineinfo_currtoken(comp_ctx);
65205
65206 /*
65207 * Function name (if any)
65208 *
65209 * We don't check for prohibited names here, because we don't
65210 * yet know whether the function will be strict. Function body
65211 * parsing handles this retroactively.
65212 *
65213 * For function expressions and declarations function name must
65214 * be an Identifer (excludes reserved words). For setter/getter
65215 * it is a PropertyName which allows reserved words and also
65216 * strings and numbers (e.g. "{ get 1() { ... } }").
65217 */
65218
65219 if (is_setget) {
65220 /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
65221 if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
65222 comp_ctx->curr_token.t == DUK_TOK_STRING) {
65223 duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
65224 } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
65225 duk_push_number(ctx, comp_ctx->curr_token.num);
65226 duk_to_string(ctx, -1);
65227 } else {
65228 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
65229 }
65230 comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
65231 DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
65232 duk__advance(comp_ctx);
65233 } else {
65234 /* Function name is an Identifier (not IdentifierName), but we get
65235 * the raw name (not recognizing keywords) here and perform the name
65236 * checks only after pass 1.
65237 */
65238 if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER) {
65239 duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
65240 comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
65241 DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
65242 duk__advance(comp_ctx);
65243 } else {
65244 /* valstack will be unbalanced, which is OK */
65245 DUK_ASSERT(!is_setget);
65246 if (is_decl) {
65247 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
65248 }
65249 }
65250 }
65251
65252 DUK_DDD(DUK_DDDPRINT("function name: %!O",
65253 (duk_heaphdr *) comp_ctx->curr_func.h_name));
65254
65255 /*
65256 * Formal argument list
65257 *
65258 * We don't check for prohibited names or for duplicate argument
65259 * names here, becase we don't yet know whether the function will
65260 * be strict. Function body parsing handles this retroactively.
65261 */
65262
65263 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
65264
65265 duk__parse_func_formals(comp_ctx);
65266
65267 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
65268 duk__advance(comp_ctx);
65269
65270 /*
65271 * Parse function body
65272 */
65273
65274 duk__parse_func_body(comp_ctx,
65275 0, /* expect_eof */
65276 0, /* implicit_return_value */
65277 DUK_TOK_LCURLY); /* expect_token */
65278
65279 /*
65280 * Convert duk_compiler_func to a function template and add it
65281 * to the parent function table.
65282 */
65283
65284 duk__convert_to_func_template(comp_ctx, is_setget /*force_no_namebind*/); /* -> [ ... func ] */
65285}
65286
65287/* Parse an inner function, adding the function template to the current function's
65288 * function table. Return a function number to be used by the outer function.
65289 *
65290 * Avoiding O(depth^2) inner function parsing is handled here. On the first pass,
65291 * compile and register the function normally into the 'funcs' array, also recording
65292 * a lexer point (offset/line) to the closing brace of the function. On the second
65293 * pass, skip the function and return the same 'fnum' as on the first pass by using
65294 * a running counter.
65295 *
65296 * An unfortunate side effect of this is that when parsing the inner function, almost
65297 * nothing is known of the outer function, i.e. the inner function's scope. We don't
65298 * need that information at the moment, but it would allow some optimizations if it
65299 * were used.
65300 */
65301DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
65302 duk_hthread *thr = comp_ctx->thr;
65303 duk_context *ctx = (duk_context *) thr;
65304 duk_compiler_func old_func;
65305 duk_idx_t entry_top;
65306 duk_int_t fnum;
65307
65308 /*
65309 * On second pass, skip the function.
65310 */
65311
65312 if (!comp_ctx->curr_func.in_scanning) {
65313 duk_lexer_point lex_pt;
65314
65315 fnum = comp_ctx->curr_func.fnum_next++;
65316 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
65317 lex_pt.offset = duk_to_int(ctx, -1);
65318 duk_pop(ctx);
65319 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
65320 lex_pt.line = duk_to_int(ctx, -1);
65321 duk_pop(ctx);
65322
65323 DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
65324 (long) lex_pt.offset, (long) lex_pt.line));
65325
65326 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
65327 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
65328 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
65329 duk__advance(comp_ctx);
65330 duk__advance_expect(comp_ctx, DUK_TOK_RCURLY);
65331
65332 return fnum;
65333 }
65334
65335 /*
65336 * On first pass, perform actual parsing. Remember valstack top on entry
65337 * to restore it later, and switch to using a new function in comp_ctx.
65338 */
65339
65340 entry_top = duk_get_top(ctx);
65341 DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
65342 (long) entry_top, (long) comp_ctx->curr_token.start_offset));
65343
65344 DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
65345
65346 DUK_MEMZERO(&comp_ctx->curr_func, sizeof(duk_compiler_func));
65347 duk__init_func_valstack_slots(comp_ctx);
65348 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
65349
65350 /* inherit initial strictness from parent */
65351 comp_ctx->curr_func.is_strict = old_func.is_strict;
65352
65353 DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
65354 comp_ctx->curr_func.is_function = 1;
65355 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
65356 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
65357 comp_ctx->curr_func.is_setget = is_setget;
65358 comp_ctx->curr_func.is_decl = is_decl;
65359
65360 /*
65361 * Parse inner function
65362 */
65363
65364 duk__parse_func_like_raw(comp_ctx, is_decl, is_setget); /* pushes function template */
65365
65366 /* prev_token.start_offset points to the closing brace here; when skipping
65367 * we're going to reparse the closing brace to ensure semicolon insertion
65368 * etc work as expected.
65369 */
65370 DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld",
65371 (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset));
65372 DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
65373
65374 /* XXX: append primitive */
65375 DUK_ASSERT(duk_get_length(ctx, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
65376 fnum = old_func.fnum_next++;
65377
65378 if (fnum > DUK__MAX_FUNCS) {
65379 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT);
65380 }
65381
65382 /* array writes autoincrement length */
65383 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
65384 duk_push_size_t(ctx, comp_ctx->prev_token.start_offset);
65385 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
65386 duk_push_int(ctx, comp_ctx->prev_token.start_line);
65387 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
65388
65389 /*
65390 * Cleanup: restore original function, restore valstack state.
65391 */
65392
65393 DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
65394 duk_set_top(ctx, entry_top);
65395
65396 DUK_ASSERT_TOP(ctx, entry_top);
65397
65398 return fnum;
65399}
65400
65401/*
65402 * Compile input string into an executable function template without
65403 * arguments.
65404 *
65405 * The string is parsed as the "Program" production of Ecmascript E5.
65406 * Compilation context can be either global code or eval code (see E5
65407 * Sections 14 and 15.1.2.1).
65408 *
65409 * Input stack: [ ... filename ]
65410 * Output stack: [ ... func_template ]
65411 */
65412
65413/* XXX: source code property */
65414
65415DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
65416 duk_hthread *thr = (duk_hthread *) ctx;
65417 duk_hstring *h_filename;
65418 duk__compiler_stkstate *comp_stk;
65419 duk_compiler_ctx *comp_ctx;
65420 duk_lexer_point *lex_pt;
65421 duk_compiler_func *func;
65422 duk_idx_t entry_top;
65423 duk_bool_t is_strict;
65424 duk_bool_t is_eval;
65425 duk_bool_t is_funcexpr;
65426 duk_small_uint_t flags;
65427
65428 DUK_ASSERT(thr != NULL);
65429
65430 /*
65431 * Arguments check
65432 */
65433
65434 entry_top = duk_get_top(ctx);
65435 DUK_ASSERT(entry_top >= 2);
65436
65437 comp_stk = (duk__compiler_stkstate *) duk_require_pointer(ctx, -1);
65438 comp_ctx = &comp_stk->comp_ctx_alloc;
65439 lex_pt = &comp_stk->lex_pt_alloc;
65440 DUK_ASSERT(comp_ctx != NULL);
65441 DUK_ASSERT(lex_pt != NULL);
65442
65443 flags = comp_stk->flags;
65444 is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0);
65445 is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0);
65446 is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0);
65447
65448 h_filename = duk_get_hstring(ctx, -2); /* may be undefined */
65449
65450 /*
65451 * Init compiler and lexer contexts
65452 */
65453
65454 func = &comp_ctx->curr_func;
65455#ifdef DUK_USE_EXPLICIT_NULL_INIT
65456 comp_ctx->thr = NULL;
65457 comp_ctx->h_filename = NULL;
65458 comp_ctx->prev_token.str1 = NULL;
65459 comp_ctx->prev_token.str2 = NULL;
65460 comp_ctx->curr_token.str1 = NULL;
65461 comp_ctx->curr_token.str2 = NULL;
65462#endif
65463
65464 duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
65465
65466 duk_push_dynamic_buffer(ctx, 0); /* entry_top + 0 */
65467 duk_push_undefined(ctx); /* entry_top + 1 */
65468 duk_push_undefined(ctx); /* entry_top + 2 */
65469 duk_push_undefined(ctx); /* entry_top + 3 */
65470 duk_push_undefined(ctx); /* entry_top + 4 */
65471
65472 comp_ctx->thr = thr;
65473 comp_ctx->h_filename = h_filename;
65474 comp_ctx->tok11_idx = entry_top + 1;
65475 comp_ctx->tok12_idx = entry_top + 2;
65476 comp_ctx->tok21_idx = entry_top + 3;
65477 comp_ctx->tok22_idx = entry_top + 4;
65478 comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT;
65479
65480 /* comp_ctx->lex has been pre-initialized by caller: it has been
65481 * zeroed and input/input_length has been set.
65482 */
65483 comp_ctx->lex.thr = thr;
65484 /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */
65485 comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
65486 comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
65487 comp_ctx->lex.buf_idx = entry_top + 0;
65488 comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 0);
65489 DUK_ASSERT(comp_ctx->lex.buf != NULL);
65490 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
65491 comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
65492
65493 lex_pt->offset = 0;
65494 lex_pt->line = 1;
65495 DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt); /* fills window */
65496 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
65497
65498 /*
65499 * Initialize function state for a zero-argument function
65500 */
65501
65502 duk__init_func_valstack_slots(comp_ctx);
65503 DUK_ASSERT(func->num_formals == 0);
65504
65505 if (is_funcexpr) {
65506 /* Name will be filled from function expression, not by caller.
65507 * This case is used by Function constructor and duk_compile()
65508 * API with the DUK_COMPILE_FUNCTION option.
65509 */
65510 DUK_ASSERT(func->h_name == NULL);
65511 } else {
65512 duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
65513 DUK_STRIDX_GLOBAL));
65514 func->h_name = duk_get_hstring(ctx, -1);
65515 }
65516
65517 /*
65518 * Parse a function body or a function-like expression, depending
65519 * on flags.
65520 */
65521
65522 func->is_strict = is_strict;
65523 func->is_setget = 0;
65524 func->is_decl = 0;
65525
65526 if (is_funcexpr) {
65527 func->is_function = 1;
65528 func->is_eval = 0;
65529 func->is_global = 0;
65530
65531 duk__advance(comp_ctx); /* init 'curr_token' */
65532 duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
65533 (void) duk__parse_func_like_raw(comp_ctx,
65534 0, /* is_decl */
65535 0); /* is_setget */
65536 } else {
65537 func->is_function = 0;
65538 func->is_eval = is_eval;
65539 func->is_global = !is_eval;
65540
65541 duk__parse_func_body(comp_ctx,
65542 1, /* expect_eof */
65543 1, /* implicit_return_value */
65544 -1); /* expect_token */
65545 }
65546
65547 /*
65548 * Convert duk_compiler_func to a function template
65549 */
65550
65551 duk__convert_to_func_template(comp_ctx, 0 /*force_no_namebind*/);
65552
65553 /*
65554 * Wrapping duk_safe_call() will mangle the stack, just return stack top
65555 */
65556
65557 /* [ ... filename (temps) func ] */
65558
65559 return 1;
65560}
65561
65562DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
65563 duk_context *ctx = (duk_context *) thr;
65564 duk__compiler_stkstate comp_stk;
65565 duk_compiler_ctx *prev_ctx;
65566 duk_ret_t safe_rc;
65567
65568 /* XXX: this illustrates that a C catchpoint implemented using duk_safe_call()
65569 * is a bit heavy at the moment. The wrapper compiles to ~180 bytes on x64.
65570 * Alternatives would be nice.
65571 */
65572
65573 DUK_ASSERT(thr != NULL);
65574 DUK_ASSERT(src_buffer != NULL);
65575
65576 /* preinitialize lexer state partially */
65577 DUK_MEMZERO(&comp_stk, sizeof(comp_stk));
65578 comp_stk.flags = flags;
65579 DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex);
65580 comp_stk.comp_ctx_alloc.lex.input = src_buffer;
65581 comp_stk.comp_ctx_alloc.lex.input_length = src_length;
65582
65583 duk_push_pointer(ctx, (void *) &comp_stk);
65584
65585 /* [ ... filename &comp_stk ] */
65586
65587 prev_ctx = thr->compile_ctx;
65588 thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */
65589 safe_rc = duk_safe_call(ctx, duk__js_compile_raw, 2 /*nargs*/, 1 /*nret*/);
65590 thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
65591
65592 if (safe_rc != DUK_EXEC_SUCCESS) {
65593 duk_throw(ctx);
65594 }
65595
65596 /* [ ... template ] */
65597}
65598#line 1 "duk_js_executor.c"
65599/*
65600 * Ecmascript bytecode executor.
65601 */
65602
65603/* include removed: duk_internal.h */
65604
65605/*
65606 * Local declarations.
65607 */
65608
65609DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top);
65610
65611/*
65612 * Arithmetic, binary, and logical helpers.
65613 *
65614 * Note: there is no opcode for logical AND or logical OR; this is on
65615 * purpose, because the evalution order semantics for them make such
65616 * opcodes pretty pointless: short circuiting means they are most
65617 * comfortably implemented as jumps. However, a logical NOT opcode
65618 * is useful.
65619 *
65620 * Note: careful with duk_tval pointers here: they are potentially
65621 * invalidated by any DECREF and almost any API call. It's still
65622 * preferable to work without making a copy but that's not always
65623 * possible.
65624 */
65625
65626DUK_LOCAL duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
65627 /*
65628 * Ecmascript modulus ('%') does not match IEEE 754 "remainder"
65629 * operation (implemented by remainder() in C99) but does seem
65630 * to match ANSI C fmod().
65631 *
65632 * Compare E5 Section 11.5.3 and "man fmod".
65633 */
65634
65635 return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
65636}
65637
65638DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) {
65639 /*
65640 * Addition operator is different from other arithmetic
65641 * operations in that it also provides string concatenation.
65642 * Hence it is implemented separately.
65643 *
65644 * There is a fast path for number addition. Other cases go
65645 * through potentially multiple coercions as described in the
65646 * E5 specification. It may be possible to reduce the number
65647 * of coercions, but this must be done carefully to preserve
65648 * the exact semantics.
65649 *
65650 * E5 Section 11.6.1.
65651 *
65652 * Custom types also have special behavior implemented here.
65653 */
65654
65655 duk_context *ctx = (duk_context *) thr;
65656 duk_double_union du;
65657
65658 DUK_ASSERT(thr != NULL);
65659 DUK_ASSERT(ctx != NULL);
65660 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
65661 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
65662 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
65663 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
65664
65665 /*
65666 * Fast paths
65667 */
65668
65669#if defined(DUK_USE_FASTINT)
65670 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
65671 duk_int64_t v1, v2, v3;
65672 duk_int32_t v3_hi;
65673 duk_tval *tv_z;
65674
65675 /* Input values are signed 48-bit so we can detect overflow
65676 * reliably from high bits or just a comparison.
65677 */
65678
65679 v1 = DUK_TVAL_GET_FASTINT(tv_x);
65680 v2 = DUK_TVAL_GET_FASTINT(tv_y);
65681 v3 = v1 + v2;
65682 v3_hi = (duk_int32_t) (v3 >> 32);
65683 if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
65684 tv_z = thr->valstack_bottom + idx_z;
65685 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
65686 return;
65687 } else {
65688 /* overflow, fall through */
65689 ;
65690 }
65691 }
65692#endif /* DUK_USE_FASTINT */
65693
65694 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
65695 duk_tval *tv_z;
65696
65697 du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
65698 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
65699 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
65700
65701 tv_z = thr->valstack_bottom + idx_z;
65702 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
65703 return;
65704 }
65705
65706 /*
65707 * Slow path: potentially requires function calls for coercion
65708 */
65709
65710 duk_push_tval(ctx, tv_x);
65711 duk_push_tval(ctx, tv_y);
65712 duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
65713 duk_to_primitive(ctx, -1, DUK_HINT_NONE);
65714
65715 /* As a first approximation, buffer values are coerced to strings
65716 * for addition. This means that adding two buffers currently
65717 * results in a string.
65718 */
65719 if (duk_check_type_mask(ctx, -2, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER) ||
65720 duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER)) {
65721 duk_to_string(ctx, -2);
65722 duk_to_string(ctx, -1);
65723 duk_concat(ctx, 2); /* [... s1 s2] -> [... s1+s2] */
65724 duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
65725 } else {
65726 duk_double_t d1, d2;
65727
65728 d1 = duk_to_number(ctx, -2);
65729 d2 = duk_to_number(ctx, -1);
65730 DUK_ASSERT(duk_is_number(ctx, -2));
65731 DUK_ASSERT(duk_is_number(ctx, -1));
65732 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
65733 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
65734
65735 du.d = d1 + d2;
65736 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
65737 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
65738
65739 duk_pop_2(ctx);
65740 duk_push_number(ctx, du.d);
65741 duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
65742 }
65743}
65744
65745DUK_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) {
65746 /*
65747 * Arithmetic operations other than '+' have number-only semantics
65748 * and are implemented here. The separate switch-case here means a
65749 * "double dispatch" of the arithmetic opcode, but saves code space.
65750 *
65751 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
65752 */
65753
65754 duk_context *ctx = (duk_context *) thr;
65755 duk_tval *tv_z;
65756 duk_double_t d1, d2;
65757 duk_double_union du;
65758
65759 DUK_ASSERT(thr != NULL);
65760 DUK_ASSERT(ctx != NULL);
65761 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
65762 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
65763 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
65764 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
65765
65766#if defined(DUK_USE_FASTINT)
65767 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
65768 duk_int64_t v1, v2, v3;
65769 duk_int32_t v3_hi;
65770
65771 v1 = DUK_TVAL_GET_FASTINT(tv_x);
65772 v2 = DUK_TVAL_GET_FASTINT(tv_y);
65773
65774 switch (opcode) {
65775 case DUK_OP_SUB: {
65776 v3 = v1 - v2;
65777 break;
65778 }
65779 case DUK_OP_MUL: {
65780 /* Must ensure result is 64-bit (no overflow); a
65781 * simple and sufficient fast path is to allow only
65782 * 32-bit inputs. Avoid zero inputs to avoid
65783 * negative zero issues (-1 * 0 = -0, for instance).
65784 */
65785 if (v1 >= -0x80000000LL && v1 <= 0x7fffffffLL && v1 != 0 &&
65786 v2 >= -0x80000000LL && v2 <= 0x7fffffffLL && v2 != 0) {
65787 v3 = v1 * v2;
65788 } else {
65789 goto skip_fastint;
65790 }
65791 break;
65792 }
65793 case DUK_OP_DIV: {
65794 /* Don't allow a zero divisor. Fast path check by
65795 * "verifying" with multiplication. Also avoid zero
65796 * dividend to avoid negative zero issues (0 / -1 = -0
65797 * for instance).
65798 */
65799 if (v1 == 0 || v2 == 0) {
65800 goto skip_fastint;
65801 }
65802 v3 = v1 / v2;
65803 if (v3 * v2 != v1) {
65804 goto skip_fastint;
65805 }
65806 break;
65807 }
65808 case DUK_OP_MOD: {
65809 /* Don't allow a zero divisor. Restrict both v1 and
65810 * v2 to positive values to avoid compiler specific
65811 * behavior.
65812 */
65813 if (v1 < 1 || v2 < 1) {
65814 goto skip_fastint;
65815 }
65816 v3 = v1 % v2;
65817 DUK_ASSERT(v3 >= 0);
65818 DUK_ASSERT(v3 < v2);
65819 DUK_ASSERT(v1 - (v1 / v2) * v2 == v3);
65820 break;
65821 }
65822 default: {
65823 DUK_UNREACHABLE();
65824 goto skip_fastint;
65825 }
65826 }
65827
65828 v3_hi = (duk_int32_t) (v3 >> 32);
65829 if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
65830 tv_z = thr->valstack_bottom + idx_z;
65831 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
65832 return;
65833 }
65834 /* fall through if overflow etc */
65835 }
65836 skip_fastint:
65837#endif /* DUK_USE_FASTINT */
65838
65839 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
65840 /* fast path */
65841 d1 = DUK_TVAL_GET_NUMBER(tv_x);
65842 d2 = DUK_TVAL_GET_NUMBER(tv_y);
65843 } else {
65844 duk_push_tval(ctx, tv_x);
65845 duk_push_tval(ctx, tv_y);
65846 d1 = duk_to_number(ctx, -2); /* side effects */
65847 d2 = duk_to_number(ctx, -1);
65848 DUK_ASSERT(duk_is_number(ctx, -2));
65849 DUK_ASSERT(duk_is_number(ctx, -1));
65850 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
65851 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
65852 duk_pop_2(ctx);
65853 }
65854
65855 switch (opcode) {
65856 case DUK_OP_SUB: {
65857 du.d = d1 - d2;
65858 break;
65859 }
65860 case DUK_OP_MUL: {
65861 du.d = d1 * d2;
65862 break;
65863 }
65864 case DUK_OP_DIV: {
65865 du.d = d1 / d2;
65866 break;
65867 }
65868 case DUK_OP_MOD: {
65869 du.d = duk__compute_mod(d1, d2);
65870 break;
65871 }
65872 default: {
65873 DUK_UNREACHABLE();
65874 du.d = DUK_DOUBLE_NAN; /* should not happen */
65875 break;
65876 }
65877 }
65878
65879 /* important to use normalized NaN with 8-byte tagged types */
65880 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
65881 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
65882
65883 tv_z = thr->valstack_bottom + idx_z;
65884 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
65885}
65886
65887DUK_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) {
65888 /*
65889 * Binary bitwise operations use different coercions (ToInt32, ToUint32)
65890 * depending on the operation. We coerce the arguments first using
65891 * ToInt32(), and then cast to an 32-bit value if necessary. Note that
65892 * such casts must be correct even if there is no native 32-bit type
65893 * (e.g., duk_int32_t and duk_uint32_t are 64-bit).
65894 *
65895 * E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
65896 */
65897
65898 duk_context *ctx = (duk_context *) thr;
65899 duk_tval *tv_z;
65900 duk_int32_t i1, i2, i3;
65901 duk_uint32_t u1, u2, u3;
65902#if defined(DUK_USE_FASTINT)
65903 duk_int64_t fi3;
65904#else
65905 duk_double_t d3;
65906#endif
65907
65908 DUK_ASSERT(thr != NULL);
65909 DUK_ASSERT(ctx != NULL);
65910 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
65911 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
65912 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
65913 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
65914
65915#if defined(DUK_USE_FASTINT)
65916 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
65917 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
65918 i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y);
65919 }
65920 else
65921#endif /* DUK_USE_FASTINT */
65922 {
65923 duk_push_tval(ctx, tv_x);
65924 duk_push_tval(ctx, tv_y);
65925 i1 = duk_to_int32(ctx, -2);
65926 i2 = duk_to_int32(ctx, -1);
65927 duk_pop_2(ctx);
65928 }
65929
65930 switch (opcode) {
65931 case DUK_OP_BAND: {
65932 i3 = i1 & i2;
65933 break;
65934 }
65935 case DUK_OP_BOR: {
65936 i3 = i1 | i2;
65937 break;
65938 }
65939 case DUK_OP_BXOR: {
65940 i3 = i1 ^ i2;
65941 break;
65942 }
65943 case DUK_OP_BASL: {
65944 /* Signed shift, named "arithmetic" (asl) because the result
65945 * is signed, e.g. 4294967295 << 1 -> -2. Note that result
65946 * must be masked.
65947 */
65948
65949 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
65950 i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL)); /* E5 Section 11.7.1, steps 7 and 8 */
65951 i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */
65952 break;
65953 }
65954 case DUK_OP_BASR: {
65955 /* signed shift */
65956
65957 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
65958 i3 = i1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
65959 break;
65960 }
65961 case DUK_OP_BLSR: {
65962 /* unsigned shift */
65963
65964 u1 = ((duk_uint32_t) i1) & 0xffffffffUL;
65965 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
65966
65967 /* special result value handling */
65968 u3 = u1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
65969#if defined(DUK_USE_FASTINT)
65970 fi3 = (duk_int64_t) u3;
65971 goto fastint_result_set;
65972#else
65973 d3 = (duk_double_t) u3;
65974 goto result_set;
65975#endif
65976 }
65977 default: {
65978 DUK_UNREACHABLE();
65979 i3 = 0; /* should not happen */
65980 break;
65981 }
65982 }
65983
65984#if defined(DUK_USE_FASTINT)
65985 /* Result is always fastint compatible. */
65986 /* XXX: Set 32-bit result (but must then handle signed and
65987 * unsigned results separately).
65988 */
65989 fi3 = (duk_int64_t) i3;
65990
65991 fastint_result_set:
65992 tv_z = thr->valstack_bottom + idx_z;
65993 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */
65994#else
65995 d3 = (duk_double_t) i3;
65996
65997 result_set:
65998 DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */
65999 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */
66000
66001 tv_z = thr->valstack_bottom + idx_z;
66002 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */
66003#endif
66004}
66005
66006/* In-place unary operation. */
66007DUK_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) {
66008 /*
66009 * Arithmetic operations other than '+' have number-only semantics
66010 * and are implemented here. The separate switch-case here means a
66011 * "double dispatch" of the arithmetic opcode, but saves code space.
66012 *
66013 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
66014 */
66015
66016 duk_context *ctx = (duk_context *) thr;
66017 duk_double_t d1;
66018 duk_double_union du;
66019
66020 DUK_ASSERT(thr != NULL);
66021 DUK_ASSERT(ctx != NULL);
66022 DUK_ASSERT(opcode == DUK_EXTRAOP_UNM || opcode == DUK_EXTRAOP_UNP);
66023 DUK_ASSERT(tv_x != NULL);
66024 DUK_ASSERT(idx_x >= 0);
66025
66026#if defined(DUK_USE_FASTINT)
66027 if (DUK_TVAL_IS_FASTINT(tv_x)) {
66028 duk_int64_t v1, v2;
66029
66030 v1 = DUK_TVAL_GET_FASTINT(tv_x);
66031 if (opcode == DUK_EXTRAOP_UNM) {
66032 /* The smallest fastint is no longer 48-bit when
66033 * negated. Positive zero becames negative zero
66034 * (cannot be represented) when negated.
66035 */
66036 if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
66037 v2 = -v1;
66038 DUK_TVAL_SET_FASTINT(tv_x, v2); /* no refcount changes */
66039 return;
66040 }
66041 } else {
66042 /* ToNumber() for a fastint is a no-op. */
66043 DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
66044 return;
66045 }
66046 /* fall through if overflow etc */
66047 }
66048#endif /* DUK_USE_FASTINT */
66049
66050 if (!DUK_TVAL_IS_NUMBER(tv_x)) {
66051 duk_to_number(ctx, idx_x); /* side effects, perform in-place */
66052 tv_x = DUK_GET_TVAL_POSIDX(ctx, idx_x);
66053 DUK_ASSERT(tv_x != NULL);
66054 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
66055 }
66056
66057 d1 = DUK_TVAL_GET_NUMBER(tv_x);
66058 if (opcode == DUK_EXTRAOP_UNM) {
66059 du.d = -d1;
66060 } else {
66061 /* ToNumber() for a double is a no-op. */
66062 DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
66063 du.d = d1;
66064 }
66065 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */
66066
66067 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
66068
66069#if defined(DUK_USE_FASTINT)
66070 /* Unary plus is used to force a fastint check, so must include
66071 * downgrade check.
66072 */
66073 DUK_TVAL_SET_NUMBER_CHKFAST(tv_x, du.d); /* no refcount changes */
66074#else
66075 DUK_TVAL_SET_NUMBER(tv_x, du.d); /* no refcount changes */
66076#endif
66077}
66078
66079DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_uint_fast_t idx_z) {
66080 /*
66081 * E5 Section 11.4.8
66082 */
66083
66084 duk_context *ctx = (duk_context *) thr;
66085 duk_tval *tv_z;
66086 duk_int32_t i1, i2;
66087#if !defined(DUK_USE_FASTINT)
66088 duk_double_t d2;
66089#endif
66090
66091 DUK_ASSERT(thr != NULL);
66092 DUK_ASSERT(ctx != NULL);
66093 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
66094 DUK_ASSERT_DISABLE(idx_z >= 0);
66095 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
66096
66097#if defined(DUK_USE_FASTINT)
66098 if (DUK_TVAL_IS_FASTINT(tv_x)) {
66099 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
66100 }
66101 else
66102#endif /* DUK_USE_FASTINT */
66103 {
66104 duk_push_tval(ctx, tv_x);
66105 i1 = duk_to_int32(ctx, -1);
66106 duk_pop(ctx);
66107 }
66108
66109 i2 = ~i1;
66110
66111#if defined(DUK_USE_FASTINT)
66112 /* Result is always fastint compatible. */
66113 tv_z = thr->valstack_bottom + idx_z;
66114 DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv_z, i2); /* side effects */
66115#else
66116 d2 = (duk_double_t) i2;
66117
66118 DUK_ASSERT(!DUK_ISNAN(d2)); /* 'val' is never NaN, so no need to normalize */
66119 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); /* always normalized */
66120
66121 tv_z = thr->valstack_bottom + idx_z;
66122 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d2); /* side effects */
66123#endif
66124}
66125
66126DUK_LOCAL void duk__vm_logical_not(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_z) {
66127 /*
66128 * E5 Section 11.4.9
66129 */
66130
66131 duk_bool_t res;
66132
66133 DUK_ASSERT(thr != NULL);
66134 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
66135 DUK_ASSERT(tv_z != NULL); /* reg */
66136
66137 DUK_UNREF(thr); /* w/o refcounts */
66138
66139 /* ToBoolean() does not require any operations with side effects so
66140 * we can do it efficiently. For footprint it would be better to use
66141 * duk_js_toboolean() and then push+replace to the result slot.
66142 */
66143 res = duk_js_toboolean(tv_x); /* does not modify tv_x */
66144 DUK_ASSERT(res == 0 || res == 1);
66145 res ^= 1;
66146 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv_z, res); /* side effects */
66147}
66148
66149/*
66150 * Longjmp and other control flow transfer for the bytecode executor.
66151 *
66152 * The longjmp handler can handle all longjmp types: error, yield, and
66153 * resume (pseudotypes are never actually thrown).
66154 *
66155 * Error policy for longjmp: should not ordinarily throw errors; if errors
66156 * occur (e.g. due to out-of-memory) they bubble outwards rather than being
66157 * handled recursively.
66158 */
66159
66160#define DUK__LONGJMP_RESTART 0 /* state updated, restart bytecode execution */
66161#define DUK__LONGJMP_RETHROW 1 /* exit bytecode executor by rethrowing an error to caller */
66162
66163#define DUK__RETHAND_RESTART 0 /* state updated, restart bytecode execution */
66164#define DUK__RETHAND_FINISHED 1 /* exit bytecode execution with return value */
66165
66166/* XXX: optimize reconfig valstack operations so that resize, clamp, and setting
66167 * top are combined into one pass.
66168 */
66169
66170/* Reconfigure value stack for return to an Ecmascript function at 'act_idx'. */
66171DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr, duk_size_t act_idx) {
66172 duk_activation *act;
66173 duk_hcompiledfunction *h_func;
66174 duk_idx_t clamp_top;
66175
66176 DUK_ASSERT(thr != NULL);
66177 DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
66178 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
66179 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
66180 DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
66181
66182 /* Clamp so that values at 'clamp_top' and above are wiped and won't
66183 * retain reachable garbage. Then extend to 'nregs' because we're
66184 * returning to an Ecmascript function.
66185 */
66186
66187 act = thr->callstack + act_idx;
66188 h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
66189
66190 thr->valstack_bottom = thr->valstack + act->idx_bottom;
66191 DUK_ASSERT(act->idx_retval >= act->idx_bottom);
66192 clamp_top = (duk_idx_t) (act->idx_retval - act->idx_bottom + 1); /* +1 = one retval */
66193 duk_set_top((duk_context *) thr, clamp_top);
66194 act = NULL;
66195
66196 (void) duk_valstack_resize_raw((duk_context *) thr,
66197 (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
66198 h_func->nregs + /* reg count */
66199 DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
66200 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
66201 0 /* no compact */ |
66202 DUK_VSRESIZE_FLAG_THROW);
66203
66204 duk_set_top((duk_context *) thr, h_func->nregs);
66205}
66206
66207DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_size_t act_idx, duk_size_t cat_idx) {
66208 duk_activation *act;
66209 duk_catcher *cat;
66210 duk_hcompiledfunction *h_func;
66211 duk_idx_t clamp_top;
66212
66213 DUK_ASSERT(thr != NULL);
66214 DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
66215 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
66216 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
66217 DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
66218
66219 act = thr->callstack + act_idx;
66220 cat = thr->catchstack + cat_idx;
66221 h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
66222
66223 thr->valstack_bottom = thr->valstack + act->idx_bottom;
66224 DUK_ASSERT(cat->idx_base >= act->idx_bottom);
66225 clamp_top = (duk_idx_t) (cat->idx_base - act->idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
66226 duk_set_top((duk_context *) thr, clamp_top);
66227 act = NULL;
66228 cat = NULL;
66229
66230 (void) duk_valstack_resize_raw((duk_context *) thr,
66231 (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
66232 h_func->nregs + /* reg count */
66233 DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
66234 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
66235 0 /* no compact */ |
66236 DUK_VSRESIZE_FLAG_THROW);
66237
66238 duk_set_top((duk_context *) thr, h_func->nregs);
66239}
66240
66241/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. */
66242DUK_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) {
66243 duk_tval *tv1;
66244
66245 DUK_ASSERT(thr != NULL);
66246 DUK_ASSERT(tv_val_unstable != NULL);
66247
66248 tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base;
66249 DUK_ASSERT(tv1 < thr->valstack_top);
66250 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
66251
66252 tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base + 1;
66253 DUK_ASSERT(tv1 < thr->valstack_top);
66254
66255 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) lj_type); /* side effects */
66256}
66257
66258DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
66259 duk_context *ctx;
66260 duk_activation *act;
66261
66262 DUK_ASSERT(thr != NULL);
66263 DUK_ASSERT(tv_val_unstable != NULL);
66264 ctx = (duk_context *) thr;
66265
66266 duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
66267
66268 duk_hthread_catchstack_unwind(thr, cat_idx + 1);
66269 duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
66270
66271 DUK_ASSERT(thr->callstack_top >= 1);
66272 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
66273 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
66274
66275 duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
66276
66277 DUK_ASSERT(thr->callstack_top >= 1);
66278 act = thr->callstack + thr->callstack_top - 1;
66279 act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */
66280 act = NULL;
66281
66282 /*
66283 * If entering a 'catch' block which requires an automatic
66284 * catch variable binding, create the lexical environment.
66285 *
66286 * The binding is mutable (= writable) but not deletable.
66287 * Step 4 for the catch production in E5 Section 12.14;
66288 * no value is given for CreateMutableBinding 'D' argument,
66289 * which implies the binding is not deletable.
66290 */
66291
66292 if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) {
66293 duk_hobject *new_env;
66294 duk_hobject *act_lex_env;
66295
66296 DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding"));
66297
66298 /* Note: 'act' is dangerous here because it may get invalidate at many
66299 * points, so we re-lookup it multiple times.
66300 */
66301 DUK_ASSERT(thr->callstack_top >= 1);
66302 act = thr->callstack + thr->callstack_top - 1;
66303
66304 if (act->lex_env == NULL) {
66305 DUK_ASSERT(act->var_env == NULL);
66306 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
66307
66308 /* this may have side effects, so re-lookup act */
66309 duk_js_init_activation_environment_records_delayed(thr, act);
66310 act = thr->callstack + thr->callstack_top - 1;
66311 }
66312 DUK_ASSERT(act->lex_env != NULL);
66313 DUK_ASSERT(act->var_env != NULL);
66314 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
66315 DUK_UNREF(act); /* unreferenced without assertions */
66316
66317 act = thr->callstack + thr->callstack_top - 1;
66318 act_lex_env = act->lex_env;
66319 act = NULL; /* invalidated */
66320
66321 (void) duk_push_object_helper_proto(ctx,
66322 DUK_HOBJECT_FLAG_EXTENSIBLE |
66323 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
66324 act_lex_env);
66325 new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
66326 DUK_ASSERT(new_env != NULL);
66327 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
66328
66329 /* Note: currently the catch binding is handled without a register
66330 * binding because we don't support dynamic register bindings (they
66331 * must be fixed for an entire function). So, there is no need to
66332 * record regbases etc.
66333 */
66334
66335 DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL);
66336 duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname);
66337 duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base);
66338 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
66339
66340 act = thr->callstack + thr->callstack_top - 1;
66341 act->lex_env = new_env;
66342 DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */
66343
66344 DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]);
66345
66346 duk_pop(ctx);
66347
66348 DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
66349 }
66350
66351 DUK_CAT_CLEAR_CATCH_ENABLED(&thr->catchstack[cat_idx]);
66352}
66353
66354DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
66355 duk_activation *act;
66356
66357 DUK_ASSERT(thr != NULL);
66358 DUK_ASSERT(tv_val_unstable != NULL);
66359
66360 duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
66361
66362 duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */
66363 duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
66364
66365 DUK_ASSERT(thr->callstack_top >= 1);
66366 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
66367 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
66368
66369 duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
66370
66371 DUK_ASSERT(thr->callstack_top >= 1);
66372 act = thr->callstack + thr->callstack_top - 1;
66373 act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */
66374 act = NULL;
66375
66376 DUK_CAT_CLEAR_FINALLY_ENABLED(&thr->catchstack[cat_idx]);
66377}
66378
66379DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_size_t cat_idx, duk_small_uint_t lj_type) {
66380 duk_activation *act;
66381
66382 DUK_ASSERT(thr != NULL);
66383
66384 DUK_ASSERT(thr->callstack_top >= 1);
66385 act = thr->callstack + thr->callstack_top - 1;
66386
66387 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
66388 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
66389
66390 /* +0 = break, +1 = continue */
66391 act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
66392 act = NULL; /* invalidated */
66393
66394 duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */
66395 /* no need to unwind callstack */
66396
66397 /* valstack should not need changes */
66398#if defined(DUK_USE_ASSERTIONS)
66399 DUK_ASSERT(thr->callstack_top >= 1);
66400 act = thr->callstack + thr->callstack_top - 1;
66401 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
66402 (duk_size_t) ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act))->nregs);
66403#endif
66404}
66405
66406/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
66407 * when a RETURN opcode terminates a thread and yields to the resumer.
66408 */
66409DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_size_t act_idx, duk_tval *tv_val_unstable) {
66410 duk_tval *tv1;
66411
66412 DUK_ASSERT(thr != NULL);
66413 DUK_ASSERT(resumer != NULL);
66414 DUK_ASSERT(tv_val_unstable != NULL);
66415 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + act_idx) != NULL);
66416 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + act_idx))); /* resume caller must be an ecmascript func */
66417
66418 tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */
66419 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
66420
66421 duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */
66422
66423 /* no need to unwind catchstack */
66424 duk__reconfig_valstack_ecma_return(resumer, act_idx);
66425
66426 /* caller must change active thread, and set thr->resumer to NULL */
66427}
66428
66429DUK_LOCAL
66430duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
66431 duk_hthread *entry_thread,
66432 duk_size_t entry_callstack_top) {
66433 duk_size_t entry_callstack_index;
66434 duk_small_uint_t retval = DUK__LONGJMP_RESTART;
66435
66436 DUK_ASSERT(thr != NULL);
66437 DUK_ASSERT(entry_thread != NULL);
66438 DUK_ASSERT(entry_callstack_top > 0); /* guarantees entry_callstack_top - 1 >= 0 */
66439
66440 entry_callstack_index = entry_callstack_top - 1;
66441
66442 /* 'thr' is the current thread, as no-one resumes except us and we
66443 * switch 'thr' in that case.
66444 */
66445 DUK_ASSERT(thr == thr->heap->curr_thread);
66446
66447 /*
66448 * (Re)try handling the longjmp.
66449 *
66450 * A longjmp handler may convert the longjmp to a different type and
66451 * "virtually" rethrow by goto'ing to 'check_longjmp'. Before the goto,
66452 * the following must be updated:
66453 * - the heap 'lj' state
66454 * - 'thr' must reflect the "throwing" thread
66455 */
66456
66457 check_longjmp:
66458
66459 DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld",
66460 (long) thr->heap->lj.type,
66461 (duk_tval *) &thr->heap->lj.value1,
66462 (duk_tval *) &thr->heap->lj.value2,
66463 (long) thr->heap->lj.iserror));
66464
66465 switch (thr->heap->lj.type) {
66466
66467 case DUK_LJ_TYPE_RESUME: {
66468 /*
66469 * Note: lj.value1 is 'value', lj.value2 is 'resumee'.
66470 * This differs from YIELD.
66471 */
66472
66473 duk_tval *tv;
66474 duk_tval *tv2;
66475 duk_size_t act_idx;
66476 duk_hthread *resumee;
66477
66478 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
66479
66480 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */
66481 DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
66482 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
66483 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
66484 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume);
66485 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
66486 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
66487 DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
66488
66489 tv = &thr->heap->lj.value2; /* resumee */
66490 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
66491 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
66492 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
66493 resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
66494
66495 DUK_ASSERT(resumee != NULL);
66496 DUK_ASSERT(resumee->resumer == NULL);
66497 DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE ||
66498 resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */
66499 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66500 resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */
66501 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66502 (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL &&
66503 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) &&
66504 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield));
66505 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66506 (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2) != NULL &&
66507 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2)))); /* an Ecmascript function */
66508 DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66509 (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */
66510 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
66511 resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */
66512 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
66513 (resumee->valstack_top == resumee->valstack + 1 &&
66514 DUK_TVAL_IS_OBJECT(resumee->valstack_top - 1) &&
66515 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(resumee->valstack_top - 1))));
66516
66517 if (thr->heap->lj.iserror) {
66518 /*
66519 * Throw the error in the resumed thread's context; the
66520 * error value is pushed onto the resumee valstack.
66521 *
66522 * Note: the callstack of the target may empty in this case
66523 * too (i.e. the target thread has never been resumed). The
66524 * value stack will contain the initial function in that case,
66525 * which we simply ignore.
66526 */
66527
66528 resumee->resumer = thr;
66529 resumee->state = DUK_HTHREAD_STATE_RUNNING;
66530 thr->state = DUK_HTHREAD_STATE_RESUMED;
66531 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
66532 thr = resumee;
66533
66534 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
66535
66536 /* thr->heap->lj.value1 is already the value to throw */
66537 /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */
66538
66539 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
66540
66541 DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
66542 goto check_longjmp;
66543 } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
66544 act_idx = resumee->callstack_top - 2; /* Ecmascript function */
66545 DUK_ASSERT_DISABLE(resumee->callstack[act_idx].idx_retval >= 0); /* unsigned */
66546
66547 tv = resumee->valstack + resumee->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.yield() */
66548 DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
66549 tv2 = &thr->heap->lj.value1;
66550 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */
66551
66552 duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */
66553
66554 /* no need to unwind catchstack */
66555
66556 duk__reconfig_valstack_ecma_return(resumee, act_idx);
66557
66558 resumee->resumer = thr;
66559 resumee->state = DUK_HTHREAD_STATE_RUNNING;
66560 thr->state = DUK_HTHREAD_STATE_RESUMED;
66561 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
66562#if 0
66563 thr = resumee; /* not needed, as we exit right away */
66564#endif
66565 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
66566 retval = DUK__LONGJMP_RESTART;
66567 goto wipe_and_return;
66568 } else {
66569 duk_small_uint_t call_flags;
66570 duk_bool_t setup_rc;
66571
66572 /* resumee: [... initial_func] (currently actually: [initial_func]) */
66573
66574 duk_push_undefined((duk_context *) resumee);
66575 tv = &thr->heap->lj.value1;
66576 duk_push_tval((duk_context *) resumee, tv);
66577
66578 /* resumee: [... initial_func undefined(= this) resume_value ] */
66579
66580 call_flags = DUK_CALL_FLAG_IS_RESUME; /* is resume, not a tail call */
66581
66582 setup_rc = duk_handle_ecma_call_setup(resumee,
66583 1, /* num_stack_args */
66584 call_flags); /* call_flags */
66585 if (setup_rc == 0) {
66586 /* Shouldn't happen but check anyway. */
66587 DUK_ERROR_INTERNAL_DEFMSG(thr);
66588 }
66589
66590 resumee->resumer = thr;
66591 resumee->state = DUK_HTHREAD_STATE_RUNNING;
66592 thr->state = DUK_HTHREAD_STATE_RESUMED;
66593 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
66594#if 0
66595 thr = resumee; /* not needed, as we exit right away */
66596#endif
66597 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
66598 retval = DUK__LONGJMP_RESTART;
66599 goto wipe_and_return;
66600 }
66601 DUK_UNREACHABLE();
66602 break; /* never here */
66603 }
66604
66605 case DUK_LJ_TYPE_YIELD: {
66606 /*
66607 * Currently only allowed only if yielding thread has only
66608 * Ecmascript activations (except for the Duktape.Thread.yield()
66609 * call at the callstack top) and none of them constructor
66610 * calls.
66611 *
66612 * This excludes the 'entry' thread which will always have
66613 * a preventcount > 0.
66614 */
66615
66616 duk_hthread *resumer;
66617
66618 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
66619
66620 DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */
66621 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */
66622 DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */
66623 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
66624 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
66625 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield);
66626 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
66627 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
66628 DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
66629
66630 resumer = thr->resumer;
66631
66632 DUK_ASSERT(resumer != NULL);
66633 DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */
66634 DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
66635 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL &&
66636 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) &&
66637 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume);
66638 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL &&
66639 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */
66640 DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
66641
66642 if (thr->heap->lj.iserror) {
66643 thr->state = DUK_HTHREAD_STATE_YIELDED;
66644 thr->resumer = NULL;
66645 resumer->state = DUK_HTHREAD_STATE_RUNNING;
66646 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
66647 thr = resumer;
66648
66649 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
66650 /* lj.value1 is already set */
66651 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
66652
66653 DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
66654 goto check_longjmp;
66655 } else {
66656 duk__handle_yield(thr, resumer, resumer->callstack_top - 2, &thr->heap->lj.value1);
66657
66658 thr->state = DUK_HTHREAD_STATE_YIELDED;
66659 thr->resumer = NULL;
66660 resumer->state = DUK_HTHREAD_STATE_RUNNING;
66661 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
66662#if 0
66663 thr = resumer; /* not needed, as we exit right away */
66664#endif
66665
66666 DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer"));
66667 retval = DUK__LONGJMP_RESTART;
66668 goto wipe_and_return;
66669 }
66670 DUK_UNREACHABLE();
66671 break; /* never here */
66672 }
66673
66674 case DUK_LJ_TYPE_THROW: {
66675 /*
66676 * Three possible outcomes:
66677 * * A try or finally catcher is found => resume there.
66678 * (or)
66679 * * The error propagates to the bytecode executor entry
66680 * level (and we're in the entry thread) => rethrow
66681 * with a new longjmp(), after restoring the previous
66682 * catchpoint.
66683 * * The error is not caught in the current thread, so
66684 * the thread finishes with an error. This works like
66685 * a yielded error, except that the thread is finished
66686 * and can no longer be resumed. (There is always a
66687 * resumer in this case.)
66688 *
66689 * Note: until we hit the entry level, there can only be
66690 * Ecmascript activations.
66691 */
66692
66693 duk_catcher *cat;
66694 duk_hthread *resumer;
66695
66696 cat = thr->catchstack + thr->catchstack_top - 1;
66697 while (cat >= thr->catchstack) {
66698 if (thr == entry_thread &&
66699 cat->callstack_index < entry_callstack_index) {
66700 /* entry level reached */
66701 break;
66702 }
66703
66704 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
66705 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
66706
66707 duk__handle_catch(thr,
66708 cat - thr->catchstack,
66709 &thr->heap->lj.value1,
66710 DUK_LJ_TYPE_THROW);
66711
66712 DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
66713 retval = DUK__LONGJMP_RESTART;
66714 goto wipe_and_return;
66715 }
66716
66717 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
66718 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
66719 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
66720
66721 duk__handle_finally(thr,
66722 cat - thr->catchstack,
66723 &thr->heap->lj.value1,
66724 DUK_LJ_TYPE_THROW);
66725
66726 DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
66727 retval = DUK__LONGJMP_RESTART;
66728 goto wipe_and_return;
66729 }
66730
66731 cat--;
66732 }
66733
66734 if (thr == entry_thread) {
66735 /* not caught by anything before entry level; rethrow and let the
66736 * final catcher unwind everything
66737 */
66738#if 0
66739 duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
66740 duk_hthread_callstack_unwind(thr, entry_callstack_index + 1);
66741
66742#endif
66743 DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
66744 retval = DUK__LONGJMP_RETHROW;
66745 goto just_return;
66746 /* Note: MUST NOT wipe_and_return here, as heap->lj must remain intact */
66747 }
66748
66749 DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
66750
66751 /* not caught by current thread, thread terminates (yield error to resumer);
66752 * note that this may cause a cascade if the resumer terminates with an uncaught
66753 * exception etc (this is OK, but needs careful testing)
66754 */
66755
66756 DUK_ASSERT(thr->resumer != NULL);
66757 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
66758 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
66759 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
66760 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
66761 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
66762 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
66763
66764 resumer = thr->resumer;
66765
66766 /* reset longjmp */
66767
66768 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); /* already set */
66769 /* lj.value1 already set */
66770
66771 duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
66772 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
66773
66774 thr->resumer = NULL;
66775 resumer->state = DUK_HTHREAD_STATE_RUNNING;
66776 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
66777 thr = resumer;
66778 goto check_longjmp;
66779 }
66780
66781 case DUK_LJ_TYPE_BREAK: /* pseudotypes, not used in actual longjmps */
66782 case DUK_LJ_TYPE_CONTINUE:
66783 case DUK_LJ_TYPE_RETURN:
66784 case DUK_LJ_TYPE_NORMAL:
66785 default: {
66786 /* should never happen, but be robust */
66787 DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error", (long) thr->heap->lj.type));
66788 goto convert_to_internal_error;
66789 }
66790
66791 } /* end switch */
66792
66793 DUK_UNREACHABLE();
66794
66795 wipe_and_return:
66796 /* this is not strictly necessary, but helps debugging */
66797 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
66798 thr->heap->lj.iserror = 0;
66799
66800 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
66801 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
66802
66803 just_return:
66804 return retval;
66805
66806 convert_to_internal_error:
66807 /* This could also be thrown internally (set the error, goto check_longjmp),
66808 * but it's better for internal errors to bubble outwards so that we won't
66809 * infinite loop in this catchpoint.
66810 */
66811 DUK_ERROR_INTERNAL_DEFMSG(thr);
66812 DUK_UNREACHABLE();
66813 return retval;
66814}
66815
66816/* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE
66817 * handling because it has a measurable performance impact in ordinary
66818 * environments and an extreme impact in Emscripten (GH-342).
66819 */
66820DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
66821 duk_uint_t label_id,
66822 duk_small_uint_t lj_type) {
66823 duk_catcher *cat;
66824 duk_size_t orig_callstack_index;
66825
66826 DUK_ASSERT(thr != NULL);
66827
66828 /*
66829 * Find a matching label catcher or 'finally' catcher in
66830 * the same function.
66831 *
66832 * A label catcher must always exist and will match unless
66833 * a 'finally' captures the break/continue first. It is the
66834 * compiler's responsibility to ensure that labels are used
66835 * correctly.
66836 */
66837
66838 /* Note: thr->catchstack_top may be 0, so that cat < thr->catchstack
66839 * initially. This is OK and intended.
66840 */
66841 cat = thr->catchstack + thr->catchstack_top - 1;
66842 DUK_ASSERT(thr->callstack_top > 0);
66843 orig_callstack_index = thr->callstack_top - 1;
66844
66845 DUK_DDD(DUK_DDDPRINT("handling break/continue with label=%ld, callstack index=%ld",
66846 (long) label_id, (long) cat->callstack_index));
66847
66848 while (cat >= thr->catchstack) {
66849 if (cat->callstack_index != orig_callstack_index) {
66850 break;
66851 }
66852 DUK_DDD(DUK_DDDPRINT("considering catcher %ld: type=%ld label=%ld",
66853 (long) (cat - thr->catchstack),
66854 (long) DUK_CAT_GET_TYPE(cat),
66855 (long) DUK_CAT_GET_LABEL(cat)));
66856
66857 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
66858 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
66859 duk_size_t cat_idx;
66860 duk_tval tv_tmp;
66861
66862 cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
66863
66864 DUK_TVAL_SET_FASTINT_U32(&tv_tmp, (duk_uint32_t) label_id);
66865 duk__handle_finally(thr, cat_idx, &tv_tmp, lj_type);
66866
66867 DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
66868 return;
66869 }
66870 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
66871 (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
66872 duk_size_t cat_idx;
66873
66874 cat_idx = (duk_size_t) (cat - thr->catchstack);
66875 duk__handle_label(thr, cat_idx, lj_type);
66876
66877 DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
66878 return;
66879 }
66880 cat--;
66881 }
66882
66883 /* should never happen, but be robust */
66884 DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
66885 DUK_ERROR_INTERNAL_DEFMSG(thr);
66886 return;
66887}
66888
66889/* Handle a RETURN opcode. Avoid using longjmp() for return handling because
66890 * it has a measurable performance impact in ordinary environments and an extreme
66891 * impact in Emscripten (GH-342). Return value is on value stack top.
66892 */
66893DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
66894 duk_hthread *entry_thread,
66895 duk_size_t entry_callstack_top) {
66896 duk_tval *tv1;
66897 duk_tval *tv2;
66898 duk_hthread *resumer;
66899 duk_catcher *cat;
66900 duk_size_t new_cat_top;
66901 duk_size_t orig_callstack_index;
66902
66903 /* We can directly access value stack here. */
66904
66905 DUK_ASSERT(thr != NULL);
66906 DUK_ASSERT(entry_thread != NULL);
66907 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
66908 tv1 = thr->valstack_top - 1;
66909 DUK_TVAL_CHKFAST_INPLACE(tv1); /* fastint downgrade check for return values */
66910
66911 /*
66912 * Four possible outcomes:
66913 *
66914 * 1. A 'finally' in the same function catches the 'return'.
66915 * It may continue to propagate when 'finally' is finished,
66916 * or it may be neutralized by 'finally' (both handled by
66917 * ENDFIN).
66918 *
66919 * 2. The return happens at the entry level of the bytecode
66920 * executor, so return from the executor (in C stack).
66921 *
66922 * 3. There is a calling (Ecmascript) activation in the call
66923 * stack => return to it, in the same executor instance.
66924 *
66925 * 4. There is no calling activation, and the thread is
66926 * terminated. There is always a resumer in this case,
66927 * which gets the return value similarly to a 'yield'
66928 * (except that the current thread can no longer be
66929 * resumed).
66930 */
66931
66932 DUK_ASSERT(thr != NULL);
66933 DUK_ASSERT(thr->callstack_top >= 1);
66934 DUK_ASSERT(thr->catchstack != NULL);
66935
66936 /* XXX: does not work if thr->catchstack is NULL */
66937 /* XXX: does not work if thr->catchstack is allocated but lowest pointer */
66938
66939 cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */
66940 DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */
66941 orig_callstack_index = thr->callstack_top - 1;
66942
66943 while (cat >= thr->catchstack) {
66944 if (cat->callstack_index != orig_callstack_index) {
66945 break;
66946 }
66947 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
66948 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
66949 duk_size_t cat_idx;
66950
66951 cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
66952
66953 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
66954 duk__handle_finally(thr, cat_idx, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
66955
66956 DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
66957 return DUK__RETHAND_RESTART;
66958 }
66959 cat--;
66960 }
66961 /* If out of catchstack, cat = thr->catchstack - 1;
66962 * new_cat_top will be 0 in that case.
66963 */
66964 new_cat_top = (duk_size_t) ((cat + 1) - thr->catchstack);
66965 cat = NULL; /* avoid referencing, invalidated */
66966
66967 DUK_DDD(DUK_DDDPRINT("no catcher in catch stack, return to calling activation / yield"));
66968
66969 if (thr == entry_thread &&
66970 thr->callstack_top == entry_callstack_top) {
66971 /* Return to the bytecode executor caller which will unwind stacks.
66972 * Return value is already on the stack top: [ ... retval ].
66973 */
66974
66975 /* XXX: could unwind catchstack here, so that call handling
66976 * didn't need to do that?
66977 */
66978 DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
66979 return DUK__RETHAND_FINISHED;
66980 }
66981
66982 if (thr->callstack_top >= 2) {
66983 /* There is a caller; it MUST be an Ecmascript caller (otherwise it would
66984 * match entry level check)
66985 */
66986
66987 DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T",
66988 (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
66989 (duk_tval *) &thr->heap->lj.value1));
66990
66991 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */
66992
66993 tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval;
66994 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
66995 tv2 = thr->valstack_top - 1;
66996 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
66997
66998 DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T",
66999 (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
67000 (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval)));
67001
67002 duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
67003 duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
67004 duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1);
67005
67006 DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
67007 return DUK__RETHAND_RESTART;
67008 }
67009
67010 DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)"));
67011
67012 DUK_ASSERT(thr->resumer != NULL);
67013 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
67014 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
67015 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
67016 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
67017 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
67018 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
67019 DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
67020 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
67021 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
67022
67023 resumer = thr->resumer;
67024
67025 /* Share yield longjmp handler. */
67026 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
67027 duk__handle_yield(thr, resumer, resumer->callstack_top - 2, thr->valstack_top - 1);
67028
67029 duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
67030 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
67031
67032 thr->resumer = NULL;
67033 resumer->state = DUK_HTHREAD_STATE_RUNNING;
67034 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
67035#if 0
67036 thr = resumer; /* not needed */
67037#endif
67038
67039 DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer"));
67040 return DUK__RETHAND_RESTART;
67041}
67042
67043/*
67044 * Executor interrupt handling
67045 *
67046 * The handler is called whenever the interrupt countdown reaches zero
67047 * (or below). The handler must perform whatever checks are activated,
67048 * e.g. check for cumulative step count to impose an execution step
67049 * limit or check for breakpoints or other debugger interaction.
67050 *
67051 * When the actions are done, the handler must reinit the interrupt
67052 * init and counter values. The 'init' value must indicate how many
67053 * bytecode instructions are executed before the next interrupt. The
67054 * counter must interface with the bytecode executor loop. Concretely,
67055 * the new init value is normally one higher than the new counter value.
67056 * For instance, to execute exactly one bytecode instruction the init
67057 * value is set to 1 and the counter to 0. If an error is thrown by the
67058 * interrupt handler, the counters are set to the same value (e.g. both
67059 * to 0 to cause an interrupt when the next bytecode instruction is about
67060 * to be executed after error handling).
67061 *
67062 * Maintaining the init/counter value properly is important for accurate
67063 * behavior. For instance, executor step limit needs a cumulative step
67064 * count which is simply computed as a sum of 'init' values. This must
67065 * work accurately even when single stepping.
67066 */
67067
67068#if defined(DUK_USE_INTERRUPT_COUNTER)
67069
67070#define DUK__INT_NOACTION 0 /* no specific action, resume normal execution */
67071#define DUK__INT_RESTART 1 /* must "goto restart_execution", e.g. breakpoints changed */
67072
67073#if defined(DUK_USE_DEBUGGER_SUPPORT)
67074DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
67075 duk_context *ctx;
67076 duk_activation *act;
67077 duk_breakpoint *bp;
67078 duk_breakpoint **bp_active;
67079 duk_uint_fast32_t line = 0;
67080 duk_bool_t process_messages;
67081 duk_bool_t processed_messages = 0;
67082
67083 DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */
67084
67085 ctx = (duk_context *) thr;
67086 act = thr->callstack + thr->callstack_top - 1;
67087
67088 /* It might seem that replacing 'thr->heap' with just 'heap' below
67089 * might be a good idea, but it increases code size slightly
67090 * (probably due to unnecessary spilling) at least on x64.
67091 */
67092
67093 /*
67094 * Breakpoint and step state checks
67095 */
67096
67097 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
67098 (thr->heap->dbg_step_thread == thr &&
67099 thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
67100 line = duk_debug_curr_line(thr);
67101
67102 if (act->prev_line != line) {
67103 /* Stepped? Step out is handled by callstack unwind. */
67104 if ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
67105 thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
67106 (thr->heap->dbg_step_thread == thr) &&
67107 (thr->heap->dbg_step_csindex == thr->callstack_top - 1) &&
67108 (line != thr->heap->dbg_step_startline)) {
67109 DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld",
67110 (long) line));
67111
67112 DUK_HEAP_SET_PAUSED(thr->heap);
67113 }
67114
67115 /* Check for breakpoints only on line transition.
67116 * Breakpoint is triggered when we enter the target
67117 * line from a different line, and the previous line
67118 * was within the same function.
67119 *
67120 * This condition is tricky: the condition used to be
67121 * that transition to -or across- the breakpoint line
67122 * triggered the breakpoint. This seems intuitively
67123 * better because it handles breakpoints on lines with
67124 * no emitted opcodes; but this leads to the issue
67125 * described in: https://github.com/svaarala/duktape/issues/263.
67126 */
67127 bp_active = thr->heap->dbg_breakpoints_active;
67128 for (;;) {
67129 bp = *bp_active++;
67130 if (bp == NULL) {
67131 break;
67132 }
67133
67134 DUK_ASSERT(bp->filename != NULL);
67135 if (act->prev_line != bp->line && line == bp->line) {
67136 DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld",
67137 (duk_heaphdr *) bp->filename, (long) bp->line));
67138
67139 DUK_HEAP_SET_PAUSED(thr->heap);
67140 }
67141 }
67142 } else {
67143 ;
67144 }
67145
67146 act->prev_line = line;
67147 }
67148
67149 /*
67150 * Rate limit check for sending status update or peeking into
67151 * the debug transport. Both can be expensive operations that
67152 * we don't want to do on every opcode.
67153 *
67154 * Making sure the interval remains reasonable on a wide variety
67155 * of targets and bytecode is difficult without a timestamp, so
67156 * we use a Date-provided timestamp for the rate limit check.
67157 * But since it's also expensive to get a timestamp, a bytecode
67158 * counter is used to rate limit getting timestamps.
67159 */
67160
67161 process_messages = 0;
67162 if (thr->heap->dbg_state_dirty || thr->heap->dbg_paused || thr->heap->dbg_detaching) {
67163 /* Enter message processing loop for sending Status notifys and
67164 * to finish a pending detach.
67165 */
67166 process_messages = 1;
67167 }
67168
67169 /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
67170 thr->heap->dbg_exec_counter += thr->interrupt_init;
67171 if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
67172 /* Overflow of the execution counter is fine and doesn't break
67173 * anything here.
67174 */
67175
67176 duk_double_t now, diff_last;
67177
67178 thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
67179 now = DUK_USE_DATE_GET_NOW(ctx);
67180
67181 diff_last = now - thr->heap->dbg_last_time;
67182 if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
67183 /* Negative value checked so that a "time jump" works
67184 * reasonably.
67185 *
67186 * Same interval is now used for status sending and
67187 * peeking.
67188 */
67189
67190 thr->heap->dbg_last_time = now;
67191 thr->heap->dbg_state_dirty = 1;
67192 process_messages = 1;
67193 }
67194 }
67195
67196 /*
67197 * Process messages and send status if necessary.
67198 *
67199 * If we're paused, we'll block for new messages. If we're not
67200 * paused, we'll process anything we can peek but won't block
67201 * for more. Detach (and re-attach) handling is all localized
67202 * to duk_debug_process_messages() too.
67203 *
67204 * Debugger writes outside the message loop may cause debugger
67205 * detach1 phase to run, after which dbg_read_cb == NULL and
67206 * dbg_detaching != 0. The message loop will finish the detach
67207 * by running detach2 phase, so enter the message loop also when
67208 * detaching.
67209 */
67210
67211 act = NULL; /* may be changed */
67212 if (process_messages) {
67213 DUK_ASSERT(thr->heap->dbg_processing == 0);
67214 processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
67215 DUK_ASSERT(thr->heap->dbg_processing == 0);
67216 }
67217
67218 /* Continue checked execution if there are breakpoints or we're stepping.
67219 * Also use checked execution if paused flag is active - it shouldn't be
67220 * because the debug message loop shouldn't terminate if it was. Step out
67221 * is handled by callstack unwind and doesn't need checked execution.
67222 * Note that debugger may have detached due to error or explicit request
67223 * above, so we must recheck attach status.
67224 */
67225
67226 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
67227 act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */
67228 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
67229 ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
67230 thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
67231 thr->heap->dbg_step_thread == thr &&
67232 thr->heap->dbg_step_csindex == thr->callstack_top - 1) ||
67233 thr->heap->dbg_paused) {
67234 *out_immediate = 1;
67235 }
67236
67237 /* If we processed any debug messages breakpoints may have
67238 * changed; restart execution to re-check active breakpoints.
67239 */
67240 if (processed_messages) {
67241 DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
67242 *out_interrupt_retval = DUK__INT_RESTART;
67243 }
67244 } else {
67245 DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
67246 }
67247}
67248#endif /* DUK_USE_DEBUGGER_SUPPORT */
67249
67250DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
67251 duk_int_t ctr;
67252 duk_activation *act;
67253 duk_hcompiledfunction *fun;
67254 duk_bool_t immediate = 0;
67255 duk_small_uint_t retval;
67256
67257 DUK_ASSERT(thr != NULL);
67258 DUK_ASSERT(thr->heap != NULL);
67259 DUK_ASSERT(thr->callstack != NULL);
67260 DUK_ASSERT(thr->callstack_top > 0);
67261
67262#if defined(DUK_USE_DEBUG)
67263 thr->heap->inst_count_interrupt += thr->interrupt_init;
67264 DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, "
67265 "instruction counts: executor=%ld, interrupt=%ld",
67266 (long) thr->interrupt_counter, (long) thr->interrupt_init,
67267 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
67268#endif
67269
67270 retval = DUK__INT_NOACTION;
67271 ctr = DUK_HTHREAD_INTCTR_DEFAULT;
67272
67273 /*
67274 * Avoid nested calls. Concretely this happens during debugging, e.g.
67275 * when we eval() an expression.
67276 *
67277 * Also don't interrupt if we're currently doing debug processing
67278 * (which can be initiated outside the bytecode executor) as this
67279 * may cause the debugger to be called recursively. Check required
67280 * for correct operation of throw intercept and other "exotic" halting
67281 * scenarios.
67282 */
67283
67284#if defined(DUK_USE_DEBUGGER_SUPPORT)
67285 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) {
67286#else
67287 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) {
67288#endif
67289 DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring"));
67290
67291 /* Set a high interrupt counter; the original executor
67292 * interrupt invocation will rewrite before exiting.
67293 */
67294 thr->interrupt_init = ctr;
67295 thr->interrupt_counter = ctr - 1;
67296 return DUK__INT_NOACTION;
67297 }
67298 DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap);
67299
67300 act = thr->callstack + thr->callstack_top - 1;
67301
67302 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
67303 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION((duk_hobject *) fun));
67304
67305 DUK_UNREF(fun);
67306
67307#if defined(DUK_USE_EXEC_TIMEOUT_CHECK)
67308 /*
67309 * Execution timeout check
67310 */
67311
67312 if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) {
67313 /* Keep throwing an error whenever we get here. The unusual values
67314 * are set this way because no instruction is ever executed, we just
67315 * throw an error until all try/catch/finally and other catchpoints
67316 * have been exhausted. Duktape/C code gets control at each protected
67317 * call but whenever it enters back into Duktape the RangeError gets
67318 * raised. User exec timeout check must consistently indicate a timeout
67319 * until we've fully bubbled out of Duktape.
67320 */
67321 DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError"));
67322 thr->interrupt_init = 0;
67323 thr->interrupt_counter = 0;
67324 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
67325 DUK_ERROR_RANGE(thr, "execution timeout");
67326 }
67327#endif /* DUK_USE_EXEC_TIMEOUT_CHECK */
67328
67329#if defined(DUK_USE_DEBUGGER_SUPPORT)
67330 if (!thr->heap->dbg_processing &&
67331 (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) {
67332 /* Avoid recursive re-entry; enter when we're attached or
67333 * detaching (to finish off the pending detach).
67334 */
67335 duk__interrupt_handle_debugger(thr, &immediate, &retval);
67336 act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */
67337 DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
67338 }
67339#endif /* DUK_USE_DEBUGGER_SUPPORT */
67340
67341 /*
67342 * Update the interrupt counter
67343 */
67344
67345 if (immediate) {
67346 /* Cause an interrupt after executing one instruction. */
67347 ctr = 1;
67348 }
67349
67350 /* The counter value is one less than the init value: init value should
67351 * indicate how many instructions are executed before interrupt. To
67352 * execute 1 instruction (after interrupt handler return), counter must
67353 * be 0.
67354 */
67355 DUK_ASSERT(ctr >= 1);
67356 thr->interrupt_init = ctr;
67357 thr->interrupt_counter = ctr - 1;
67358 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
67359
67360 return retval;
67361}
67362#endif /* DUK_USE_INTERRUPT_COUNTER */
67363
67364/*
67365 * Debugger handling for executor restart
67366 *
67367 * Check for breakpoints, stepping, etc, and figure out if we should execute
67368 * in checked or normal mode. Note that we can't do this when an activation
67369 * is created, because breakpoint status (and stepping status) may change
67370 * later, so we must recheck every time we're executing an activation.
67371 * This primitive should be side effect free to avoid changes during check.
67372 */
67373
67374#if defined(DUK_USE_DEBUGGER_SUPPORT)
67375DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompiledfunction *fun) {
67376 duk_heap *heap;
67377 duk_tval *tv_tmp;
67378 duk_hstring *filename;
67379 duk_small_uint_t bp_idx;
67380 duk_breakpoint **bp_active;
67381
67382 DUK_ASSERT(thr != NULL);
67383 DUK_ASSERT(act != NULL);
67384 DUK_ASSERT(fun != NULL);
67385
67386 heap = thr->heap;
67387 bp_active = heap->dbg_breakpoints_active;
67388 act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
67389
67390 tv_tmp = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) fun, DUK_HTHREAD_STRING_FILE_NAME(thr));
67391 if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) {
67392 filename = DUK_TVAL_GET_STRING(tv_tmp);
67393
67394 /* Figure out all active breakpoints. A breakpoint is
67395 * considered active if the current function's fileName
67396 * matches the breakpoint's fileName, AND there is no
67397 * inner function that has matching line numbers
67398 * (otherwise a breakpoint would be triggered both
67399 * inside and outside of the inner function which would
67400 * be confusing). Example:
67401 *
67402 * function foo() {
67403 * print('foo');
67404 * function bar() { <-. breakpoints in these
67405 * print('bar'); | lines should not affect
67406 * } <-' foo() execution
67407 * bar();
67408 * }
67409 *
67410 * We need a few things that are only available when
67411 * debugger support is enabled: (1) a line range for
67412 * each function, and (2) access to the function
67413 * template to access the inner functions (and their
67414 * line ranges).
67415 *
67416 * It's important to have a narrow match for active
67417 * breakpoints so that we don't enter checked execution
67418 * when that's not necessary. For instance, if we're
67419 * running inside a certain function and there's
67420 * breakpoint outside in (after the call site), we
67421 * don't want to slow down execution of the function.
67422 */
67423
67424 for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) {
67425 duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx;
67426 duk_hobject **funcs, **funcs_end;
67427 duk_hcompiledfunction *inner_fun;
67428 duk_bool_t bp_match;
67429
67430 if (bp->filename == filename &&
67431 bp->line >= fun->start_line && bp->line <= fun->end_line) {
67432 bp_match = 1;
67433 DUK_DD(DUK_DDPRINT("breakpoint filename and line match: "
67434 "%s:%ld vs. %s (line %ld vs. %ld-%ld)",
67435 DUK_HSTRING_GET_DATA(bp->filename),
67436 (long) bp->line,
67437 DUK_HSTRING_GET_DATA(filename),
67438 (long) bp->line,
67439 (long) fun->start_line,
67440 (long) fun->end_line));
67441
67442 funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun);
67443 funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, fun);
67444 while (funcs != funcs_end) {
67445 inner_fun = (duk_hcompiledfunction *) *funcs;
67446 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) inner_fun));
67447 if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) {
67448 DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint"));
67449 bp_match = 0;
67450 break;
67451 }
67452 funcs++;
67453 }
67454
67455 if (bp_match) {
67456 /* No need to check for size of bp_active list,
67457 * it's always larger than maximum number of
67458 * breakpoints.
67459 */
67460 act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
67461 *bp_active = heap->dbg_breakpoints + bp_idx;
67462 bp_active++;
67463 }
67464 }
67465 }
67466 }
67467
67468 *bp_active = NULL; /* terminate */
67469
67470 DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
67471
67472 /* Force pause if we were doing "step into" in another activation. */
67473 if (thr->heap->dbg_step_thread != NULL &&
67474 thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO &&
67475 (thr->heap->dbg_step_thread != thr ||
67476 thr->heap->dbg_step_csindex != thr->callstack_top - 1)) {
67477 DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED"));
67478 DUK_HEAP_SET_PAUSED(thr->heap);
67479 }
67480
67481 /* Force interrupt right away if we're paused or in "checked mode".
67482 * Step out is handled by callstack unwind.
67483 */
67484 if (act->flags & (DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
67485 thr->heap->dbg_paused ||
67486 (thr->heap->dbg_step_type != DUK_STEP_TYPE_OUT &&
67487 thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
67488 /* We'll need to interrupt early so recompute the init
67489 * counter to reflect the number of bytecode instructions
67490 * executed so that step counts for e.g. debugger rate
67491 * limiting are accurate.
67492 */
67493 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
67494 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
67495 thr->interrupt_counter = 0;
67496 }
67497}
67498#endif /* DUK_USE_DEBUGGER_SUPPORT */
67499
67500/*
67501 * Ecmascript bytecode executor.
67502 *
67503 * Resume execution for the current thread from its current activation.
67504 * Returns when execution would return from the entry level activation,
67505 * leaving a single return value on top of the stack. Function calls
67506 * and thread resumptions are handled internally. If an error occurs,
67507 * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level
67508 * setjmp() jmpbuf.
67509 *
67510 * Ecmascript function calls and coroutine resumptions are handled
67511 * internally (by the outer executor function) without recursive C calls.
67512 * Other function calls are handled using duk_handle_call(), increasing
67513 * C recursion depth.
67514 *
67515 * Abrupt completions (= long control tranfers) are handled either
67516 * directly by reconfiguring relevant stacks and restarting execution,
67517 * or via a longjmp. Longjmp-free handling is preferable for performance
67518 * (especially Emscripten performance), and is used for: break, continue,
67519 * and return.
67520 *
67521 * For more detailed notes, see doc/execution.rst.
67522 *
67523 * Also see doc/code-issues.rst for discussion of setjmp(), longjmp(),
67524 * and volatile.
67525 */
67526
67527/* Presence of 'fun' is config based, there's a marginal performance
67528 * difference and the best option is architecture dependent.
67529 */
67530#if defined(DUK_USE_EXEC_FUN_LOCAL)
67531#define DUK__FUN() fun
67532#else
67533#define DUK__FUN() ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1))
67534#endif
67535#define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
67536
67537/* Reg/const access macros: these are very footprint and performance sensitive
67538 * so modify with care.
67539 */
67540#define DUK__REG(x) (*(thr->valstack_bottom + (x)))
67541#define DUK__REGP(x) (thr->valstack_bottom + (x))
67542#define DUK__CONST(x) (*(consts + (x)))
67543#define DUK__CONSTP(x) (consts + (x))
67544#if 0
67545#define DUK__REGCONST(x) ((x) < DUK_BC_REGLIMIT ? DUK__REG((x)) : DUK__CONST((x) - DUK_BC_REGLIMIT))
67546#define DUK__REGCONSTP(x) ((x) < DUK_BC_REGLIMIT ? DUK__REGP((x)) : DUK__CONSTP((x) - DUK_BC_REGLIMIT))
67547#define DUK__REGCONST(x) *((((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x)))
67548#define DUK__REGCONSTP(x) (((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x))
67549#endif
67550/* This macro works when a regconst field is 9 bits, [0,0x1ff]. Adding
67551 * DUK_LIKELY/DUK_UNLIKELY increases code footprint and doesn't seem to
67552 * improve performance on x64 (and actually harms performance in some tests).
67553 */
67554#define DUK__RCISREG(x) (((x) & 0x100) == 0)
67555#define DUK__REGCONST(x) (*((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x)))
67556#define DUK__REGCONSTP(x) ((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x))
67557
67558#ifdef DUK_USE_VERBOSE_EXECUTOR_ERRORS
67559#define DUK__INTERNAL_ERROR(msg) do { \
67560 DUK_ERROR_INTERNAL(thr, (msg)); \
67561 } while (0)
67562#else
67563#define DUK__INTERNAL_ERROR(msg) do { \
67564 goto internal_error; \
67565 } while (0)
67566#endif
67567
67568#define DUK__SYNC_CURR_PC() do { \
67569 duk_activation *act; \
67570 act = thr->callstack + thr->callstack_top - 1; \
67571 act->curr_pc = curr_pc; \
67572 } while (0)
67573#define DUK__SYNC_AND_NULL_CURR_PC() do { \
67574 duk_activation *act; \
67575 act = thr->callstack + thr->callstack_top - 1; \
67576 act->curr_pc = curr_pc; \
67577 thr->ptr_curr_pc = NULL; \
67578 } while (0)
67579
67580DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
67581 duk_hthread *entry_thread,
67582 duk_size_t entry_callstack_top,
67583 duk_int_t entry_call_recursion_depth,
67584 duk_jmpbuf *entry_jmpbuf_ptr) {
67585 duk_small_uint_t lj_ret;
67586
67587 /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
67588 * before longjmp.
67589 */
67590 DUK_ASSERT(heap->curr_thread != NULL);
67591 DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
67592
67593 /* XXX: signalling the need to shrink check (only if unwound) */
67594
67595 /* Must be restored here to handle e.g. yields properly. */
67596 heap->call_recursion_depth = entry_call_recursion_depth;
67597
67598 /* Switch to caller's setjmp() catcher so that if an error occurs
67599 * during error handling, it is always propagated outwards instead
67600 * of causing an infinite loop in our own handler.
67601 */
67602 heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
67603
67604 lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
67605
67606 if (lj_ret == DUK__LONGJMP_RESTART) {
67607 /* Restart bytecode execution, possibly with a changed thread. */
67608 ;
67609 } else {
67610 /* Rethrow error to calling state. */
67611 DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
67612
67613 /* Longjmp handling has restored jmpbuf_ptr. */
67614 DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
67615
67616 /* Thread may have changed, e.g. YIELD converted to THROW. */
67617 duk_err_longjmp(heap->curr_thread);
67618 DUK_UNREACHABLE();
67619 }
67620}
67621
67622/* Outer executor with setjmp/longjmp handling. */
67623DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
67624 /* Entry level info. */
67625 duk_hthread *entry_thread;
67626 duk_size_t entry_callstack_top;
67627 duk_int_t entry_call_recursion_depth;
67628 duk_jmpbuf *entry_jmpbuf_ptr;
67629 duk_jmpbuf our_jmpbuf;
67630 duk_heap *heap;
67631
67632 DUK_ASSERT(exec_thr != NULL);
67633 DUK_ASSERT(exec_thr->heap != NULL);
67634 DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
67635 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
67636 DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
67637 DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL);
67638 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1)));
67639
67640 entry_thread = exec_thr;
67641 heap = entry_thread->heap;
67642 entry_callstack_top = entry_thread->callstack_top;
67643 entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
67644 entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
67645
67646 /*
67647 * Note: we currently assume that the setjmp() catchpoint is
67648 * not re-entrant (longjmp() cannot be called more than once
67649 * for a single setjmp()).
67650 *
67651 * See doc/code-issues.rst for notes on variable assignment
67652 * before and after setjmp().
67653 */
67654
67655 for (;;) {
67656 heap->lj.jmpbuf_ptr = &our_jmpbuf;
67657 DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
67658
67659#if defined(DUK_USE_CPP_EXCEPTIONS)
67660 try {
67661#else
67662 DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf);
67663 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
67664#endif
67665 /* Execute bytecode until returned or longjmp(). */
67666 duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
67667
67668 /* Successful return: restore jmpbuf and return to caller. */
67669 heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
67670
67671 return;
67672#if defined(DUK_USE_CPP_EXCEPTIONS)
67673 } catch (duk_internal_exception &exc) {
67674#else
67675 } else {
67676#endif
67677#if defined(DUK_USE_CPP_EXCEPTIONS)
67678 DUK_UNREF(exc);
67679#endif
67680 DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
67681
67682 duk__handle_executor_error(heap,
67683 entry_thread,
67684 entry_callstack_top,
67685 entry_call_recursion_depth,
67686 entry_jmpbuf_ptr);
67687 }
67688#if defined(DUK_USE_CPP_EXCEPTIONS)
67689 catch (std::exception &exc) {
67690 const char *what = exc.what();
67691 if (!what) {
67692 what = "unknown";
67693 }
67694 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
67695 try {
67696 DUK_ASSERT(heap->curr_thread != NULL);
67697 DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
67698 } catch (duk_internal_exception exc) {
67699 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
67700 DUK_UNREF(exc);
67701 duk__handle_executor_error(heap,
67702 entry_thread,
67703 entry_callstack_top,
67704 entry_call_recursion_depth,
67705 entry_jmpbuf_ptr);
67706 }
67707 } catch (...) {
67708 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
67709 try {
67710 DUK_ASSERT(heap->curr_thread != NULL);
67711 DUK_ERROR_API(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
67712 } catch (duk_internal_exception exc) {
67713 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
67714 DUK_UNREF(exc);
67715 duk__handle_executor_error(heap,
67716 entry_thread,
67717 entry_callstack_top,
67718 entry_call_recursion_depth,
67719 entry_jmpbuf_ptr);
67720 }
67721 }
67722#endif
67723 }
67724
67725 DUK_UNREACHABLE();
67726}
67727
67728/* Inner executor, performance critical. */
67729DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) {
67730 /* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
67731 * Critical for performance. It would be safest to make this volatile,
67732 * but that eliminates performance benefits; aliasing guarantees
67733 * should be enough though.
67734 */
67735 duk_instr_t *curr_pc; /* bytecode has a stable pointer */
67736
67737 /* Hot variables for interpretation. Critical for performance,
67738 * but must add sparingly to minimize register shuffling.
67739 */
67740 duk_hthread *thr; /* stable */
67741 duk_tval *consts; /* stable */
67742 duk_tval *consts2; /* stable; precalculated for faster lookups */
67743 duk_uint_fast32_t ins;
67744 /* 'funcs' is quite rarely used, so no local for it */
67745#if defined(DUK_USE_EXEC_FUN_LOCAL)
67746 duk_hcompiledfunction *fun;
67747#else
67748 /* 'fun' is quite rarely used, so no local for it */
67749#endif
67750
67751#ifdef DUK_USE_INTERRUPT_COUNTER
67752 duk_int_t int_ctr;
67753#endif
67754
67755#ifdef DUK_USE_ASSERTIONS
67756 duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */
67757#endif
67758
67759 /*
67760 * Restart execution by reloading thread state.
67761 *
67762 * Note that 'thr' and any thread configuration may have changed,
67763 * so all local variables are suspect and we need to reinitialize.
67764 *
67765 * The number of local variables should be kept to a minimum: if
67766 * the variables are spilled, they will need to be loaded from
67767 * memory anyway.
67768 *
67769 * Any 'goto restart_execution;' code path in opcode dispatch must
67770 * ensure 'curr_pc' is synced back to act->curr_pc before the goto
67771 * takes place.
67772 *
67773 * The interpreter must be very careful with memory pointers, as
67774 * many pointers are not guaranteed to be 'stable' and may be
67775 * reallocated and relocated on-the-fly quite easily (e.g. by a
67776 * memory allocation or a property access).
67777 *
67778 * The following are assumed to have stable pointers:
67779 * - the current thread
67780 * - the current function
67781 * - the bytecode, constant table, inner function table of the
67782 * current function (as they are a part of the function allocation)
67783 *
67784 * The following are assumed to have semi-stable pointers:
67785 * - the current activation entry: stable as long as callstack
67786 * is not changed (reallocated by growing or shrinking), or
67787 * by any garbage collection invocation (through finalizers)
67788 * - Note in particular that ANY DECREF can invalidate the
67789 * activation pointer, so for the most part a fresh lookup
67790 * is required
67791 *
67792 * The following are not assumed to have stable pointers at all:
67793 * - the value stack (registers) of the current thread
67794 * - the catch stack of the current thread
67795 *
67796 * See execution.rst for discussion.
67797 */
67798
67799 restart_execution:
67800
67801 /* Lookup current thread; use the stable 'entry_thread' for this to
67802 * avoid clobber warnings. Any valid, reachable 'thr' value would be
67803 * fine for this, so using 'entry_thread' is just to silence warnings.
67804 */
67805 thr = entry_thread->heap->curr_thread;
67806 DUK_ASSERT(thr != NULL);
67807 DUK_ASSERT(thr->callstack_top >= 1);
67808 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
67809 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
67810
67811 thr->ptr_curr_pc = &curr_pc;
67812
67813 /* Relookup and initialize dispatch loop variables. Debugger check. */
67814 {
67815 duk_activation *act;
67816#if !defined(DUK_USE_EXEC_FUN_LOCAL)
67817 duk_hcompiledfunction *fun;
67818#endif
67819
67820 /* Assume interrupt init/counter are properly initialized here. */
67821 /* Assume that thr->valstack_bottom has been set-up before getting here. */
67822
67823 act = thr->callstack + thr->callstack_top - 1;
67824 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
67825 DUK_ASSERT(fun != NULL);
67826 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
67827 consts = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, fun);
67828 DUK_ASSERT(consts != NULL);
67829 consts2 = consts - DUK_BC_REGLIMIT;
67830
67831#if defined(DUK_USE_DEBUGGER_SUPPORT)
67832 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) {
67833 duk__executor_recheck_debugger(thr, act, fun);
67834 act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */
67835 }
67836#endif /* DUK_USE_DEBUGGER_SUPPORT */
67837
67838#ifdef DUK_USE_ASSERTIONS
67839 valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack);
67840#endif
67841
67842 /* Set up curr_pc for opcode dispatch. */
67843 curr_pc = act->curr_pc;
67844 }
67845
67846 DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
67847 "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, catchstack_top=%ld, "
67848 "preventcount=%ld",
67849 (void *) thr,
67850 (long) (thr->callstack_top - 1),
67851 (void *) DUK__FUN(),
67852 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
67853 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
67854 (long) (thr->callstack_top - 1),
67855 (long) (thr->valstack_bottom - thr->valstack),
67856 (long) (thr->valstack_top - thr->valstack),
67857 (long) thr->catchstack_top,
67858 (long) thr->callstack_preventcount));
67859
67860 /* Dispatch loop. */
67861
67862 for (;;) {
67863 DUK_ASSERT(thr->callstack_top >= 1);
67864 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs);
67865 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base);
67866
67867 /* Executor interrupt counter check, used to implement breakpoints,
67868 * debugging interface, execution timeouts, etc. The counter is heap
67869 * specific but is maintained in the current thread to make the check
67870 * as fast as possible. The counter is copied back to the heap struct
67871 * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro.
67872 */
67873#if defined(DUK_USE_INTERRUPT_COUNTER)
67874 int_ctr = thr->interrupt_counter;
67875 if (DUK_LIKELY(int_ctr > 0)) {
67876 thr->interrupt_counter = int_ctr - 1;
67877 } else {
67878 /* Trigger at zero or below */
67879 duk_small_uint_t exec_int_ret;
67880
67881 /* Write curr_pc back for the debugger. */
67882 DUK_ASSERT(thr->callstack_top > 0);
67883 {
67884 duk_activation *act;
67885 act = thr->callstack + thr->callstack_top - 1;
67886 act->curr_pc = (duk_instr_t *) curr_pc;
67887 }
67888
67889 /* Force restart caused by a function return; must recheck
67890 * debugger breakpoints before checking line transitions,
67891 * see GH-303. Restart and then handle interrupt_counter
67892 * zero again.
67893 */
67894#if defined(DUK_USE_DEBUGGER_SUPPORT)
67895 if (thr->heap->dbg_force_restart) {
67896 DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution")); /* GH-303 */
67897 thr->heap->dbg_force_restart = 0;
67898 goto restart_execution;
67899 }
67900#endif
67901
67902 exec_int_ret = duk__executor_interrupt(thr);
67903 if (exec_int_ret == DUK__INT_RESTART) {
67904 /* curr_pc synced back above */
67905 goto restart_execution;
67906 }
67907 }
67908#endif /* DUK_USE_INTERRUPT_COUNTER */
67909#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
67910 /* For cross-checking during development: ensure dispatch count
67911 * matches cumulative interrupt counter init value sums.
67912 */
67913 thr->heap->inst_count_exec++;
67914#endif
67915
67916#if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG)
67917 {
67918 duk_activation *act;
67919 act = thr->callstack + thr->callstack_top - 1;
67920 DUK_ASSERT(curr_pc >= DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN()));
67921 DUK_ASSERT(curr_pc < DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, DUK__FUN()));
67922 DUK_UNREF(act); /* if debugging disabled */
67923
67924 DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I",
67925 (long) (curr_pc - DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN())),
67926 (unsigned long) *curr_pc,
67927 (long) DUK_DEC_OP(*curr_pc),
67928 (long) (thr->valstack_top - thr->valstack),
67929 (long) (thr->valstack_end - thr->valstack),
67930 (long) (DUK__FUN() ? DUK__FUN()->nregs : -1),
67931 (duk_instr_t) *curr_pc));
67932 }
67933#endif
67934
67935#if defined(DUK_USE_ASSERTIONS)
67936 /* Quite heavy assert: check valstack policy. Improper
67937 * shuffle instructions can write beyond valstack_top/end
67938 * so this check catches them in the act.
67939 */
67940 {
67941 duk_tval *tv;
67942 tv = thr->valstack_top;
67943 while (tv != thr->valstack_end) {
67944 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
67945 tv++;
67946 }
67947 }
67948#endif
67949
67950 ins = *curr_pc++;
67951
67952 /* Typing: use duk_small_(u)int_fast_t when decoding small
67953 * opcode fields (op, A, B, C) and duk_(u)int_fast_t when
67954 * decoding larger fields (e.g. BC which is 18 bits). Use
67955 * unsigned variant by default, signed when the value is used
67956 * in signed arithmetic. Using variable names such as 'a', 'b',
67957 * 'c', 'bc', etc makes it easier to spot typing mismatches.
67958 */
67959
67960 /* XXX: the best typing needs to be validated by perf measurement:
67961 * e.g. using a small type which is the cast to a larger duk_idx_t
67962 * may be slower than declaring the variable as a duk_idx_t in the
67963 * first place.
67964 */
67965
67966 /* XXX: use macros for the repetitive tval/refcount handling. */
67967
67968 switch ((int) DUK_DEC_OP(ins)) {
67969 /* XXX: switch cast? */
67970
67971 case DUK_OP_LDREG: {
67972 duk_small_uint_fast_t a;
67973 duk_uint_fast_t bc;
67974 duk_tval *tv1, *tv2;
67975
67976 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67977 bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
67978 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
67979 break;
67980 }
67981
67982 case DUK_OP_STREG: {
67983 duk_small_uint_fast_t a;
67984 duk_uint_fast_t bc;
67985 duk_tval *tv1, *tv2;
67986
67987 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67988 bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
67989 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */
67990 break;
67991 }
67992
67993 case DUK_OP_LDCONST: {
67994 duk_small_uint_fast_t a;
67995 duk_uint_fast_t bc;
67996 duk_tval *tv1, *tv2;
67997
67998 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67999 bc = DUK_DEC_BC(ins); tv2 = DUK__CONSTP(bc);
68000 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
68001 break;
68002 }
68003
68004 case DUK_OP_LDINT: {
68005 duk_small_uint_fast_t a;
68006 duk_int_fast_t bc;
68007 duk_tval *tv1;
68008#if defined(DUK_USE_FASTINT)
68009 duk_int32_t val;
68010#else
68011 duk_double_t val;
68012#endif
68013
68014#if defined(DUK_USE_FASTINT)
68015 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
68016 bc = DUK_DEC_BC(ins); val = (duk_int32_t) (bc - DUK_BC_LDINT_BIAS);
68017 DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv1, val); /* side effects */
68018#else
68019 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
68020 bc = DUK_DEC_BC(ins); val = (duk_double_t) (bc - DUK_BC_LDINT_BIAS);
68021 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv1, val); /* side effects */
68022#endif
68023 break;
68024 }
68025
68026 case DUK_OP_LDINTX: {
68027 duk_small_uint_fast_t a;
68028 duk_tval *tv1;
68029 duk_double_t val;
68030
68031 /* LDINTX is not necessarily in FASTINT range, so
68032 * no fast path for now.
68033 *
68034 * XXX: perhaps restrict LDINTX to fastint range, wider
68035 * range very rarely needed.
68036 */
68037
68038 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
68039 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
68040 val = DUK_TVAL_GET_NUMBER(tv1) * ((duk_double_t) (1L << DUK_BC_LDINTX_SHIFT)) +
68041 (duk_double_t) DUK_DEC_BC(ins);
68042#if defined(DUK_USE_FASTINT)
68043 DUK_TVAL_SET_NUMBER_CHKFAST(tv1, val);
68044#else
68045 DUK_TVAL_SET_NUMBER(tv1, val);
68046#endif
68047 break;
68048 }
68049
68050 case DUK_OP_MPUTOBJ:
68051 case DUK_OP_MPUTOBJI: {
68052 duk_context *ctx = (duk_context *) thr;
68053 duk_small_uint_fast_t a;
68054 duk_tval *tv1;
68055 duk_hobject *obj;
68056 duk_uint_fast_t idx;
68057 duk_small_uint_fast_t count;
68058
68059 /* A -> register of target object
68060 * B -> first register of key/value pair list
68061 * C -> number of key/value pairs
68062 */
68063
68064 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
68065 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
68066 obj = DUK_TVAL_GET_OBJECT(tv1);
68067
68068 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
68069 if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
68070 duk_tval *tv_ind = DUK__REGP(idx);
68071 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68072 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68073 }
68074
68075 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
68076
68077#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68078 if (DUK_UNLIKELY(idx + count * 2 > (duk_uint_fast_t) duk_get_top(ctx))) {
68079 /* XXX: use duk_is_valid_index() instead? */
68080 /* XXX: improve check; check against nregs, not against top */
68081 DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
68082 }
68083#endif
68084
68085 duk_push_hobject(ctx, obj);
68086
68087 while (count > 0) {
68088 /* XXX: faster initialization (direct access or better primitives) */
68089
68090 duk_push_tval(ctx, DUK__REGP(idx));
68091 DUK_ASSERT(duk_is_string(ctx, -1));
68092 duk_push_tval(ctx, DUK__REGP(idx + 1)); /* -> [... obj key value] */
68093 duk_xdef_prop_wec(ctx, -3); /* -> [... obj] */
68094
68095 count--;
68096 idx += 2;
68097 }
68098
68099 duk_pop(ctx); /* [... obj] -> [...] */
68100 break;
68101 }
68102
68103 case DUK_OP_MPUTARR:
68104 case DUK_OP_MPUTARRI: {
68105 duk_context *ctx = (duk_context *) thr;
68106 duk_small_uint_fast_t a;
68107 duk_tval *tv1;
68108 duk_hobject *obj;
68109 duk_uint_fast_t idx;
68110 duk_small_uint_fast_t count;
68111 duk_uint32_t arr_idx;
68112
68113 /* A -> register of target object
68114 * B -> first register of value data (start_index, value1, value2, ..., valueN)
68115 * C -> number of key/value pairs (N)
68116 */
68117
68118 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
68119 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
68120 obj = DUK_TVAL_GET_OBJECT(tv1);
68121 DUK_ASSERT(obj != NULL);
68122
68123 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
68124 if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
68125 duk_tval *tv_ind = DUK__REGP(idx);
68126 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68127 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68128 }
68129
68130 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
68131
68132#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68133 if (idx + count + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
68134 /* XXX: use duk_is_valid_index() instead? */
68135 /* XXX: improve check; check against nregs, not against top */
68136 DUK__INTERNAL_ERROR("MPUTARR out of bounds");
68137 }
68138#endif
68139
68140 tv1 = DUK__REGP(idx);
68141 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
68142 arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
68143 idx++;
68144
68145 duk_push_hobject(ctx, obj);
68146
68147 while (count > 0) {
68148 /* duk_xdef_prop() will define an own property without any array
68149 * special behaviors. We'll need to set the array length explicitly
68150 * in the end. For arrays with elisions, the compiler will emit an
68151 * explicit SETALEN which will update the length.
68152 */
68153
68154 /* XXX: because we're dealing with 'own' properties of a fresh array,
68155 * the array initializer should just ensure that the array has a large
68156 * enough array part and write the values directly into array part,
68157 * and finally set 'length' manually in the end (as already happens now).
68158 */
68159
68160 duk_push_tval(ctx, DUK__REGP(idx)); /* -> [... obj value] */
68161 duk_xdef_prop_index_wec(ctx, -2, arr_idx); /* -> [... obj] */
68162
68163 /* XXX: could use at least one fewer loop counters */
68164 count--;
68165 idx++;
68166 arr_idx++;
68167 }
68168
68169 /* XXX: E5.1 Section 11.1.4 coerces the final length through
68170 * ToUint32() which is odd but happens now as a side effect of
68171 * 'arr_idx' type.
68172 */
68173 duk_hobject_set_length(thr, obj, (duk_uint32_t) arr_idx);
68174
68175 duk_pop(ctx); /* [... obj] -> [...] */
68176 break;
68177 }
68178
68179 case DUK_OP_NEW:
68180 case DUK_OP_NEWI: {
68181 duk_context *ctx = (duk_context *) thr;
68182 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68183 duk_uint_fast_t idx;
68184 duk_small_uint_fast_t i;
68185
68186 /* A -> unused (reserved for flags, for consistency with DUK_OP_CALL)
68187 * B -> target register and start reg: constructor, arg1, ..., argN
68188 * (for DUK_OP_NEWI, 'b' is indirect)
68189 * C -> num args (N)
68190 */
68191
68192 /* duk_new() will call the constuctor using duk_handle_call().
68193 * A constructor call prevents a yield from inside the constructor,
68194 * even if the constructor is an Ecmascript function.
68195 */
68196
68197 /* Don't need to sync curr_pc here; duk_new() will do that
68198 * when it augments the created error.
68199 */
68200
68201 /* XXX: unnecessary copying of values? Just set 'top' to
68202 * b + c, and let the return handling fix up the stack frame?
68203 */
68204
68205 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
68206 if (DUK_DEC_OP(ins) == DUK_OP_NEWI) {
68207 duk_tval *tv_ind = DUK__REGP(idx);
68208 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68209 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68210 }
68211
68212#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68213 if (idx + c + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
68214 /* XXX: use duk_is_valid_index() instead? */
68215 /* XXX: improve check; check against nregs, not against top */
68216 DUK__INTERNAL_ERROR("NEW out of bounds");
68217 }
68218#endif
68219
68220 duk_require_stack(ctx, (duk_idx_t) c);
68221 duk_push_tval(ctx, DUK__REGP(idx));
68222 for (i = 0; i < c; i++) {
68223 duk_push_tval(ctx, DUK__REGP(idx + i + 1));
68224 }
68225 duk_new(ctx, (duk_idx_t) c); /* [... constructor arg1 ... argN] -> [retval] */
68226 DUK_DDD(DUK_DDDPRINT("NEW -> %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
68227 duk_replace(ctx, (duk_idx_t) idx);
68228
68229 /* When debugger is enabled, we need to recheck the activation
68230 * status after returning. This is now handled by call handling
68231 * and heap->dbg_force_restart.
68232 */
68233 break;
68234 }
68235
68236 case DUK_OP_REGEXP: {
68237#ifdef DUK_USE_REGEXP_SUPPORT
68238 duk_context *ctx = (duk_context *) thr;
68239 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68240 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68241 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68242
68243 /* A -> target register
68244 * B -> bytecode (also contains flags)
68245 * C -> escaped source
68246 */
68247
68248 duk_push_tval(ctx, DUK__REGCONSTP(c));
68249 duk_push_tval(ctx, DUK__REGCONSTP(b)); /* -> [ ... escaped_source bytecode ] */
68250 duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
68251 DUK_DDD(DUK_DDDPRINT("regexp instance: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
68252 duk_replace(ctx, (duk_idx_t) a);
68253#else
68254 /* The compiler should never emit DUK_OP_REGEXP if there is no
68255 * regexp support.
68256 */
68257 DUK__INTERNAL_ERROR("no regexp support");
68258#endif
68259
68260 break;
68261 }
68262
68263 case DUK_OP_CSREG:
68264 case DUK_OP_CSREGI: {
68265 /*
68266 * Assuming a register binds to a variable declared within this
68267 * function (a declarative binding), the 'this' for the call
68268 * setup is always 'undefined'. E5 Section 10.2.1.1.6.
68269 */
68270
68271 duk_context *ctx = (duk_context *) thr;
68272 duk_small_uint_fast_t b = DUK_DEC_B(ins); /* restricted to regs */
68273 duk_uint_fast_t idx;
68274
68275 /* A -> target register (A, A+1) for call setup
68276 * (for DUK_OP_CSREGI, 'a' is indirect)
68277 * B -> register containing target function (not type checked here)
68278 */
68279
68280 /* XXX: direct manipulation, or duk_replace_tval() */
68281
68282 /* Note: target registers a and a+1 may overlap with DUK__REGP(b).
68283 * Careful here.
68284 */
68285
68286 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
68287 if (DUK_DEC_OP(ins) == DUK_OP_CSREGI) {
68288 duk_tval *tv_ind = DUK__REGP(idx);
68289 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68290 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68291 }
68292
68293#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68294 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
68295 /* XXX: use duk_is_valid_index() instead? */
68296 /* XXX: improve check; check against nregs, not against top */
68297 DUK__INTERNAL_ERROR("CSREG out of bounds");
68298 }
68299#endif
68300
68301 duk_push_tval(ctx, DUK__REGP(b));
68302 duk_replace(ctx, (duk_idx_t) idx);
68303 duk_push_undefined(ctx);
68304 duk_replace(ctx, (duk_idx_t) (idx + 1));
68305 break;
68306 }
68307
68308 case DUK_OP_GETVAR: {
68309 duk_context *ctx = (duk_context *) thr;
68310 duk_activation *act;
68311 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68312 duk_uint_fast_t bc = DUK_DEC_BC(ins);
68313 duk_tval *tv1;
68314 duk_hstring *name;
68315
68316 tv1 = DUK__CONSTP(bc);
68317 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68318 name = DUK_TVAL_GET_STRING(tv1);
68319 DUK_ASSERT(name != NULL);
68320 DUK_DDD(DUK_DDDPRINT("GETVAR: '%!O'", (duk_heaphdr *) name));
68321 act = thr->callstack + thr->callstack_top - 1;
68322 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
68323
68324 duk_pop(ctx); /* 'this' binding is not needed here */
68325 duk_replace(ctx, (duk_idx_t) a);
68326 break;
68327 }
68328
68329 case DUK_OP_PUTVAR: {
68330 duk_activation *act;
68331 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68332 duk_uint_fast_t bc = DUK_DEC_BC(ins);
68333 duk_tval *tv1;
68334 duk_hstring *name;
68335
68336 tv1 = DUK__CONSTP(bc);
68337 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68338 name = DUK_TVAL_GET_STRING(tv1);
68339 DUK_ASSERT(name != NULL);
68340
68341 /* XXX: putvar takes a duk_tval pointer, which is awkward and
68342 * should be reworked.
68343 */
68344
68345 tv1 = DUK__REGP(a); /* val */
68346 act = thr->callstack + thr->callstack_top - 1;
68347 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
68348 break;
68349 }
68350
68351 case DUK_OP_DECLVAR: {
68352 duk_activation *act;
68353 duk_context *ctx = (duk_context *) thr;
68354 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68355 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68356 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68357 duk_tval *tv1;
68358 duk_hstring *name;
68359 duk_small_uint_t prop_flags;
68360 duk_bool_t is_func_decl;
68361 duk_bool_t is_undef_value;
68362
68363 tv1 = DUK__REGCONSTP(b);
68364 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68365 name = DUK_TVAL_GET_STRING(tv1);
68366 DUK_ASSERT(name != NULL);
68367
68368 is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0);
68369 is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0);
68370
68371 /* XXX: declvar takes an duk_tval pointer, which is awkward and
68372 * should be reworked.
68373 */
68374
68375 /* Compiler is responsible for selecting property flags (configurability,
68376 * writability, etc).
68377 */
68378 prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
68379
68380 if (is_undef_value) {
68381 duk_push_undefined(ctx);
68382 } else {
68383 duk_push_tval(ctx, DUK__REGCONSTP(c));
68384 }
68385 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
68386
68387 act = thr->callstack + thr->callstack_top - 1;
68388 if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
68389 if (is_undef_value) {
68390 /* Already declared but no initializer value
68391 * (e.g. 'var xyz;'), no-op.
68392 */
68393 } else {
68394 /* Already declared, update value. */
68395 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
68396 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
68397 }
68398 }
68399
68400 duk_pop(ctx);
68401 break;
68402 }
68403
68404 case DUK_OP_DELVAR: {
68405 duk_activation *act;
68406 duk_context *ctx = (duk_context *) thr;
68407 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68408 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68409 duk_tval *tv1;
68410 duk_hstring *name;
68411 duk_bool_t rc;
68412
68413 tv1 = DUK__REGCONSTP(b);
68414 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68415 name = DUK_TVAL_GET_STRING(tv1);
68416 DUK_ASSERT(name != NULL);
68417 DUK_DDD(DUK_DDDPRINT("DELVAR '%!O'", (duk_heaphdr *) name));
68418 act = thr->callstack + thr->callstack_top - 1;
68419 rc = duk_js_delvar_activation(thr, act, name);
68420
68421 duk_push_boolean(ctx, rc);
68422 duk_replace(ctx, (duk_idx_t) a);
68423 break;
68424 }
68425
68426 case DUK_OP_CSVAR:
68427 case DUK_OP_CSVARI: {
68428 /* 'this' value:
68429 * E5 Section 6.b.i
68430 *
68431 * The only (standard) case where the 'this' binding is non-null is when
68432 * (1) the variable is found in an object environment record, and
68433 * (2) that object environment record is a 'with' block.
68434 *
68435 */
68436
68437 duk_context *ctx = (duk_context *) thr;
68438 duk_activation *act;
68439 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68440 duk_uint_fast_t idx;
68441 duk_tval *tv1;
68442 duk_hstring *name;
68443
68444 tv1 = DUK__REGCONSTP(b);
68445 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68446 name = DUK_TVAL_GET_STRING(tv1);
68447 DUK_ASSERT(name != NULL);
68448 act = thr->callstack + thr->callstack_top - 1;
68449 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
68450
68451 /* Note: target registers a and a+1 may overlap with DUK__REGCONSTP(b)
68452 * and DUK__REGCONSTP(c). Careful here.
68453 */
68454
68455 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
68456 if (DUK_DEC_OP(ins) == DUK_OP_CSVARI) {
68457 duk_tval *tv_ind = DUK__REGP(idx);
68458 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68459 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68460 }
68461
68462#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68463 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
68464 /* XXX: use duk_is_valid_index() instead? */
68465 /* XXX: improve check; check against nregs, not against top */
68466 DUK__INTERNAL_ERROR("CSVAR out of bounds");
68467 }
68468#endif
68469
68470 duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
68471 duk_replace(ctx, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
68472 break;
68473 }
68474
68475 case DUK_OP_CLOSURE: {
68476 duk_context *ctx = (duk_context *) thr;
68477 duk_activation *act;
68478 duk_hcompiledfunction *fun;
68479 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68480 duk_uint_fast_t bc = DUK_DEC_BC(ins);
68481 duk_hobject *fun_temp;
68482
68483 /* A -> target reg
68484 * BC -> inner function index
68485 */
68486
68487 DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)",
68488 (long) a, (long) bc, (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
68489
68490 DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */
68491 DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
68492
68493 act = thr->callstack + thr->callstack_top - 1;
68494 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
68495 fun_temp = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun)[bc];
68496 DUK_ASSERT(fun_temp != NULL);
68497 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(fun_temp));
68498
68499 DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O",
68500 (void *) fun_temp, (duk_heaphdr *) fun_temp));
68501
68502 if (act->lex_env == NULL) {
68503 DUK_ASSERT(act->var_env == NULL);
68504 duk_js_init_activation_environment_records_delayed(thr, act);
68505 act = thr->callstack + thr->callstack_top - 1;
68506 }
68507 DUK_ASSERT(act->lex_env != NULL);
68508 DUK_ASSERT(act->var_env != NULL);
68509
68510 /* functions always have a NEWENV flag, i.e. they get a
68511 * new variable declaration environment, so only lex_env
68512 * matters here.
68513 */
68514 duk_js_push_closure(thr,
68515 (duk_hcompiledfunction *) fun_temp,
68516 act->var_env,
68517 act->lex_env,
68518 1 /*add_auto_proto*/);
68519 duk_replace(ctx, (duk_idx_t) a);
68520
68521 break;
68522 }
68523
68524 case DUK_OP_GETPROP: {
68525 duk_context *ctx = (duk_context *) thr;
68526 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68527 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68528 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68529 duk_tval *tv_obj;
68530 duk_tval *tv_key;
68531 duk_bool_t rc;
68532
68533 /* A -> target reg
68534 * B -> object reg/const (may be const e.g. in "'foo'[1]")
68535 * C -> key reg/const
68536 */
68537
68538 tv_obj = DUK__REGCONSTP(b);
68539 tv_key = DUK__REGCONSTP(c);
68540 DUK_DDD(DUK_DDDPRINT("GETPROP: a=%ld obj=%!T, key=%!T",
68541 (long) a,
68542 (duk_tval *) DUK__REGCONSTP(b),
68543 (duk_tval *) DUK__REGCONSTP(c)));
68544 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
68545 DUK_UNREF(rc); /* ignore */
68546 DUK_DDD(DUK_DDDPRINT("GETPROP --> %!T",
68547 (duk_tval *) duk_get_tval(ctx, -1)));
68548 tv_obj = NULL; /* invalidated */
68549 tv_key = NULL; /* invalidated */
68550
68551 duk_replace(ctx, (duk_idx_t) a); /* val */
68552 break;
68553 }
68554
68555 case DUK_OP_PUTPROP: {
68556 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68557 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68558 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68559 duk_tval *tv_obj;
68560 duk_tval *tv_key;
68561 duk_tval *tv_val;
68562 duk_bool_t rc;
68563
68564 /* A -> object reg
68565 * B -> key reg/const
68566 * C -> value reg/const
68567 *
68568 * Note: intentional difference to register arrangement
68569 * of e.g. GETPROP; 'A' must contain a register-only value.
68570 */
68571
68572 tv_obj = DUK__REGP(a);
68573 tv_key = DUK__REGCONSTP(b);
68574 tv_val = DUK__REGCONSTP(c);
68575 DUK_DDD(DUK_DDDPRINT("PUTPROP: obj=%!T, key=%!T, val=%!T",
68576 (duk_tval *) DUK__REGP(a),
68577 (duk_tval *) DUK__REGCONSTP(b),
68578 (duk_tval *) DUK__REGCONSTP(c)));
68579 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
68580 DUK_UNREF(rc); /* ignore */
68581 DUK_DDD(DUK_DDDPRINT("PUTPROP --> obj=%!T, key=%!T, val=%!T",
68582 (duk_tval *) DUK__REGP(a),
68583 (duk_tval *) DUK__REGCONSTP(b),
68584 (duk_tval *) DUK__REGCONSTP(c)));
68585 tv_obj = NULL; /* invalidated */
68586 tv_key = NULL; /* invalidated */
68587 tv_val = NULL; /* invalidated */
68588
68589 break;
68590 }
68591
68592 case DUK_OP_DELPROP: {
68593 duk_context *ctx = (duk_context *) thr;
68594 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68595 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68596 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68597 duk_tval *tv_obj;
68598 duk_tval *tv_key;
68599 duk_bool_t rc;
68600
68601 /* A -> result reg
68602 * B -> object reg
68603 * C -> key reg/const
68604 */
68605
68606 tv_obj = DUK__REGP(b);
68607 tv_key = DUK__REGCONSTP(c);
68608 rc = duk_hobject_delprop(thr, tv_obj, tv_key, DUK__STRICT());
68609 tv_obj = NULL; /* invalidated */
68610 tv_key = NULL; /* invalidated */
68611
68612 duk_push_boolean(ctx, rc);
68613 duk_replace(ctx, (duk_idx_t) a); /* result */
68614 break;
68615 }
68616
68617 case DUK_OP_CSPROP:
68618 case DUK_OP_CSPROPI: {
68619 duk_context *ctx = (duk_context *) thr;
68620 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68621 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68622 duk_uint_fast_t idx;
68623 duk_tval *tv_obj;
68624 duk_tval *tv_key;
68625 duk_bool_t rc;
68626
68627 /* E5 Section 11.2.3, step 6.a.i */
68628 /* E5 Section 10.4.3 */
68629
68630 /* XXX: allow object to be a const, e.g. in 'foo'.toString()?
68631 * On the other hand, DUK_REGCONSTP() is slower and generates
68632 * more code.
68633 */
68634
68635 tv_obj = DUK__REGP(b);
68636 tv_key = DUK__REGCONSTP(c);
68637 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
68638 DUK_UNREF(rc); /* unused */
68639 tv_obj = NULL; /* invalidated */
68640 tv_key = NULL; /* invalidated */
68641
68642 /* Note: target registers a and a+1 may overlap with DUK__REGP(b)
68643 * and DUK__REGCONSTP(c). Careful here.
68644 */
68645
68646 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
68647 if (DUK_DEC_OP(ins) == DUK_OP_CSPROPI) {
68648 duk_tval *tv_ind = DUK__REGP(idx);
68649 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68650 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68651 }
68652
68653#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68654 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
68655 /* XXX: use duk_is_valid_index() instead? */
68656 /* XXX: improve check; check against nregs, not against top */
68657 DUK__INTERNAL_ERROR("CSPROP out of bounds");
68658 }
68659#endif
68660
68661 duk_push_tval(ctx, DUK__REGP(b)); /* [ ... val obj ] */
68662 duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
68663 duk_replace(ctx, (duk_idx_t) idx); /* val */
68664 break;
68665 }
68666
68667 case DUK_OP_ADD:
68668 case DUK_OP_SUB:
68669 case DUK_OP_MUL:
68670 case DUK_OP_DIV:
68671 case DUK_OP_MOD: {
68672 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68673 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68674 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68675 duk_small_uint_fast_t op = DUK_DEC_OP(ins);
68676
68677 if (op == DUK_OP_ADD) {
68678 /*
68679 * Handling DUK_OP_ADD this way is more compact (experimentally)
68680 * than a separate case with separate argument decoding.
68681 */
68682 duk__vm_arith_add(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a);
68683 } else {
68684 duk__vm_arith_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
68685 }
68686 break;
68687 }
68688
68689 case DUK_OP_BAND:
68690 case DUK_OP_BOR:
68691 case DUK_OP_BXOR:
68692 case DUK_OP_BASL:
68693 case DUK_OP_BLSR:
68694 case DUK_OP_BASR: {
68695 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68696 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68697 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68698 duk_small_uint_fast_t op = DUK_DEC_OP(ins);
68699
68700 duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
68701 break;
68702 }
68703
68704 case DUK_OP_EQ:
68705 case DUK_OP_NEQ: {
68706 duk_context *ctx = (duk_context *) thr;
68707 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68708 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68709 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68710 duk_bool_t tmp;
68711
68712 /* E5 Sections 11.9.1, 11.9.3 */
68713 tmp = duk_js_equals(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
68714 if (DUK_DEC_OP(ins) == DUK_OP_NEQ) {
68715 tmp = !tmp;
68716 }
68717 duk_push_boolean(ctx, tmp);
68718 duk_replace(ctx, (duk_idx_t) a);
68719 break;
68720 }
68721
68722 case DUK_OP_SEQ:
68723 case DUK_OP_SNEQ: {
68724 duk_context *ctx = (duk_context *) thr;
68725 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68726 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68727 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68728 duk_bool_t tmp;
68729
68730 /* E5 Sections 11.9.1, 11.9.3 */
68731 tmp = duk_js_strict_equals(DUK__REGCONSTP(b), DUK__REGCONSTP(c));
68732 if (DUK_DEC_OP(ins) == DUK_OP_SNEQ) {
68733 tmp = !tmp;
68734 }
68735 duk_push_boolean(ctx, tmp);
68736 duk_replace(ctx, (duk_idx_t) a);
68737 break;
68738 }
68739
68740 /* Note: combining comparison ops must be done carefully because
68741 * of uncomparable values (NaN): it's not necessarily true that
68742 * (x >= y) === !(x < y). Also, evaluation order matters, and
68743 * although it would only seem to affect the compiler this is
68744 * actually not the case, because there are also run-time coercions
68745 * of the arguments (with potential side effects).
68746 *
68747 * XXX: can be combined; check code size.
68748 */
68749
68750 case DUK_OP_GT: {
68751 duk_context *ctx = (duk_context *) thr;
68752 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68753 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68754 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68755 duk_bool_t tmp;
68756
68757 /* x > y --> y < x */
68758 tmp = duk_js_compare_helper(thr,
68759 DUK__REGCONSTP(c), /* y */
68760 DUK__REGCONSTP(b), /* x */
68761 0); /* flags */
68762
68763 duk_push_boolean(ctx, tmp);
68764 duk_replace(ctx, (duk_idx_t) a);
68765 break;
68766 }
68767
68768 case DUK_OP_GE: {
68769 duk_context *ctx = (duk_context *) thr;
68770 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68771 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68772 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68773 duk_bool_t tmp;
68774
68775 /* x >= y --> not (x < y) */
68776 tmp = duk_js_compare_helper(thr,
68777 DUK__REGCONSTP(b), /* x */
68778 DUK__REGCONSTP(c), /* y */
68779 DUK_COMPARE_FLAG_EVAL_LEFT_FIRST |
68780 DUK_COMPARE_FLAG_NEGATE); /* flags */
68781
68782 duk_push_boolean(ctx, tmp);
68783 duk_replace(ctx, (duk_idx_t) a);
68784 break;
68785 }
68786
68787 case DUK_OP_LT: {
68788 duk_context *ctx = (duk_context *) thr;
68789 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68790 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68791 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68792 duk_bool_t tmp;
68793
68794 /* x < y */
68795 tmp = duk_js_compare_helper(thr,
68796 DUK__REGCONSTP(b), /* x */
68797 DUK__REGCONSTP(c), /* y */
68798 DUK_COMPARE_FLAG_EVAL_LEFT_FIRST); /* flags */
68799
68800 duk_push_boolean(ctx, tmp);
68801 duk_replace(ctx, (duk_idx_t) a);
68802 break;
68803 }
68804
68805 case DUK_OP_LE: {
68806 duk_context *ctx = (duk_context *) thr;
68807 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68808 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68809 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68810 duk_bool_t tmp;
68811
68812 /* x <= y --> not (x > y) --> not (y < x) */
68813 tmp = duk_js_compare_helper(thr,
68814 DUK__REGCONSTP(c), /* y */
68815 DUK__REGCONSTP(b), /* x */
68816 DUK_COMPARE_FLAG_NEGATE); /* flags */
68817
68818 duk_push_boolean(ctx, tmp);
68819 duk_replace(ctx, (duk_idx_t) a);
68820 break;
68821 }
68822
68823 case DUK_OP_IF: {
68824 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68825 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68826 duk_bool_t tmp;
68827
68828 tmp = duk_js_toboolean(DUK__REGCONSTP(b));
68829 if (tmp == (duk_bool_t) a) {
68830 /* if boolean matches A, skip next inst */
68831 curr_pc++;
68832 } else {
68833 ;
68834 }
68835 break;
68836 }
68837
68838 case DUK_OP_JUMP: {
68839 duk_int_fast_t abc = DUK_DEC_ABC(ins);
68840
68841 curr_pc += abc - DUK_BC_JUMP_BIAS;
68842 break;
68843 }
68844
68845 case DUK_OP_RETURN: {
68846 duk_context *ctx = (duk_context *) thr;
68847 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68848 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68849 /* duk_small_uint_fast_t c = DUK_DEC_C(ins); */
68850 duk_small_uint_t ret_result;
68851
68852 /* A -> flags
68853 * B -> return value reg/const
68854 * C -> currently unused
68855 */
68856
68857 DUK__SYNC_AND_NULL_CURR_PC();
68858
68859 /* duk__handle_return() is guaranteed never to throw, except
68860 * for potential out-of-memory situations which will then
68861 * propagate out of the executor longjmp handler.
68862 */
68863
68864 if (a & DUK_BC_RETURN_FLAG_HAVE_RETVAL) {
68865 duk_push_tval(ctx, DUK__REGCONSTP(b));
68866 } else {
68867 duk_push_undefined(ctx);
68868 }
68869 ret_result = duk__handle_return(thr,
68870 entry_thread,
68871 entry_callstack_top);
68872 if (ret_result == DUK__RETHAND_RESTART) {
68873 goto restart_execution;
68874 }
68875 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
68876
68877 DUK_DDD(DUK_DDDPRINT("exiting executor after RETURN handling"));
68878 return;
68879 }
68880
68881 case DUK_OP_CALL:
68882 case DUK_OP_CALLI: {
68883 duk_context *ctx = (duk_context *) thr;
68884 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68885 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68886 duk_uint_fast_t idx;
68887 duk_small_uint_t call_flags;
68888 duk_small_uint_t flag_tailcall;
68889 duk_small_uint_t flag_evalcall;
68890 duk_tval *tv_func;
68891 duk_hobject *obj_func;
68892 duk_bool_t setup_rc;
68893 duk_idx_t num_stack_args;
68894#if !defined(DUK_USE_EXEC_FUN_LOCAL)
68895 duk_hcompiledfunction *fun;
68896#endif
68897
68898 /* A -> flags
68899 * B -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
68900 * (for DUK_OP_CALLI, 'b' is indirect)
68901 * C -> nargs
68902 */
68903
68904 /* these are not necessarily 0 or 1 (may be other non-zero), that's ok */
68905 flag_tailcall = (a & DUK_BC_CALL_FLAG_TAILCALL);
68906 flag_evalcall = (a & DUK_BC_CALL_FLAG_EVALCALL);
68907
68908 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
68909 if (DUK_DEC_OP(ins) == DUK_OP_CALLI) {
68910 duk_tval *tv_ind = DUK__REGP(idx);
68911 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68912 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68913 }
68914
68915#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68916 if (!duk_is_valid_index(ctx, (duk_idx_t) idx)) {
68917 /* XXX: improve check; check against nregs, not against top */
68918 DUK__INTERNAL_ERROR("CALL out of bounds");
68919 }
68920#endif
68921
68922 /*
68923 * To determine whether to use an optimized Ecmascript-to-Ecmascript
68924 * call, we need to know whether the final, non-bound function is an
68925 * Ecmascript function.
68926 *
68927 * This is now implemented so that we start to do an ecma-to-ecma call
68928 * setup which will resolve the bound chain as the first thing. If the
68929 * final function is not eligible, the return value indicates that the
68930 * ecma-to-ecma call is not possible. The setup will overwrite the call
68931 * target at DUK__REGP(idx) with the final, non-bound function (which
68932 * may be a lightfunc), and fudge arguments if necessary.
68933 *
68934 * XXX: If an ecma-to-ecma call is not possible, this initial call
68935 * setup will do bound function chain resolution but won't do the
68936 * "effective this binding" resolution which is quite confusing.
68937 * Perhaps add a helper for doing bound function and effective this
68938 * binding resolution - and call that explicitly? Ecma-to-ecma call
68939 * setup and normal function handling can then assume this prestep has
68940 * been done by the caller.
68941 */
68942
68943 duk_set_top(ctx, (duk_idx_t) (idx + c + 2)); /* [ ... func this arg1 ... argN ] */
68944
68945 call_flags = 0;
68946 if (flag_tailcall) {
68947 /* We request a tail call, but in some corner cases
68948 * call handling can decide that a tail call is
68949 * actually not possible.
68950 * See: test-bug-tailcall-preventyield-assert.c.
68951 */
68952 call_flags |= DUK_CALL_FLAG_IS_TAILCALL;
68953 }
68954
68955 /* Compared to duk_handle_call():
68956 * - protected call: never
68957 * - ignore recursion limit: never
68958 */
68959 num_stack_args = c;
68960 setup_rc = duk_handle_ecma_call_setup(thr,
68961 num_stack_args,
68962 call_flags);
68963
68964 if (setup_rc) {
68965 /* Ecma-to-ecma call possible, may or may not be a tail call.
68966 * Avoid C recursion by being clever.
68967 */
68968 DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
68969 /* curr_pc synced by duk_handle_ecma_call_setup() */
68970 goto restart_execution;
68971 }
68972 DUK_ASSERT(thr->ptr_curr_pc != NULL); /* restored if ecma-to-ecma setup fails */
68973
68974 DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call not possible, target is native (may be lightfunc)"));
68975
68976 /* Recompute argument count: bound function handling may have shifted. */
68977 num_stack_args = duk_get_top(ctx) - (idx + 2);
68978 DUK_DDD(DUK_DDDPRINT("recomputed arg count: %ld\n", (long) num_stack_args));
68979
68980 tv_func = DUK__REGP(idx); /* Relookup if relocated */
68981 if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
68982
68983 call_flags = 0; /* not protected, respect reclimit, not constructor */
68984
68985 /* There is no eval() special handling here: eval() is never
68986 * automatically converted to a lightfunc.
68987 */
68988 DUK_ASSERT(DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func) != duk_bi_global_object_eval);
68989
68990 duk_handle_call_unprotected(thr,
68991 num_stack_args,
68992 call_flags);
68993
68994 /* duk_js_call.c is required to restore the stack reserve
68995 * so we only need to reset the top.
68996 */
68997#if !defined(DUK_USE_EXEC_FUN_LOCAL)
68998 fun = DUK__FUN();
68999#endif
69000 duk_set_top(ctx, (duk_idx_t) fun->nregs);
69001
69002 /* No need to reinit setjmp() catchpoint, as call handling
69003 * will store and restore our state.
69004 */
69005 } else {
69006 /* Call setup checks callability. */
69007 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_func));
69008 obj_func = DUK_TVAL_GET_OBJECT(tv_func);
69009 DUK_ASSERT(obj_func != NULL);
69010 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(obj_func));
69011
69012 /*
69013 * Other cases, use C recursion.
69014 *
69015 * If a tail call was requested we ignore it and execute a normal call.
69016 * Since Duktape 0.11.0 the compiler emits a RETURN opcode even after
69017 * a tail call to avoid test-bug-tailcall-thread-yield-resume.js.
69018 *
69019 * Direct eval call: (1) call target (before following bound function
69020 * chain) is the built-in eval() function, and (2) call was made with
69021 * the identifier 'eval'.
69022 */
69023
69024 call_flags = 0; /* not protected, respect reclimit, not constructor */
69025
69026 if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj_func) &&
69027 ((duk_hnativefunction *) obj_func)->func == duk_bi_global_object_eval) {
69028 if (flag_evalcall) {
69029 DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was 'eval' -> direct eval"));
69030 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
69031 } else {
69032 DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was not 'eval' -> indirect eval"));
69033 }
69034 }
69035
69036 duk_handle_call_unprotected(thr,
69037 num_stack_args,
69038 call_flags);
69039
69040 /* duk_js_call.c is required to restore the stack reserve
69041 * so we only need to reset the top.
69042 */
69043#if !defined(DUK_USE_EXEC_FUN_LOCAL)
69044 fun = DUK__FUN();
69045#endif
69046 duk_set_top(ctx, (duk_idx_t) fun->nregs);
69047
69048 /* No need to reinit setjmp() catchpoint, as call handling
69049 * will store and restore our state.
69050 */
69051 }
69052
69053 /* When debugger is enabled, we need to recheck the activation
69054 * status after returning. This is now handled by call handling
69055 * and heap->dbg_force_restart.
69056 */
69057 break;
69058 }
69059
69060 case DUK_OP_TRYCATCH: {
69061 duk_context *ctx = (duk_context *) thr;
69062 duk_activation *act;
69063 duk_catcher *cat;
69064 duk_tval *tv1;
69065 duk_small_uint_fast_t a;
69066 duk_uint_fast_t bc;
69067
69068 /* A -> flags
69069 * BC -> reg_catch; base register for two registers used both during
69070 * trycatch setup and when catch is triggered
69071 *
69072 * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
69073 * reg_catch + 0: catch binding variable name (string).
69074 * Automatic declarative environment is established for
69075 * the duration of the 'catch' clause.
69076 *
69077 * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
69078 * reg_catch + 0: with 'target value', which is coerced to
69079 * an object and then used as a bindind object for an
69080 * environment record. The binding is initialized here, for
69081 * the 'try' clause.
69082 *
69083 * Note that a TRYCATCH generated for a 'with' statement has no
69084 * catch or finally parts.
69085 */
69086
69087 /* XXX: TRYCATCH handling should be reworked to avoid creating
69088 * an explicit scope unless it is actually needed (e.g. function
69089 * instances or eval is executed inside the catch block). This
69090 * rework is not trivial because the compiler doesn't have an
69091 * intermediate representation. When the rework is done, the
69092 * opcode format can also be made more straightforward.
69093 */
69094
69095 /* XXX: side effect handling is quite awkward here */
69096
69097 DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
69098 "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
69099 (long) DUK_DEC_BC(ins),
69100 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
69101 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
69102 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
69103 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
69104 (unsigned long) DUK_DEC_A(ins)));
69105
69106 a = DUK_DEC_A(ins);
69107 bc = DUK_DEC_BC(ins);
69108
69109 act = thr->callstack + thr->callstack_top - 1;
69110 DUK_ASSERT(thr->callstack_top >= 1);
69111
69112 /* 'with' target must be created first, in case we run out of memory */
69113 /* XXX: refactor out? */
69114
69115 if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
69116 DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object"));
69117
69118 if (act->lex_env == NULL) {
69119 DUK_ASSERT(act->var_env == NULL);
69120 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
69121
69122 /* must relookup act in case of side effects */
69123 duk_js_init_activation_environment_records_delayed(thr, act);
69124 act = thr->callstack + thr->callstack_top - 1;
69125 DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
69126 }
69127 DUK_ASSERT(act->lex_env != NULL);
69128 DUK_ASSERT(act->var_env != NULL);
69129
69130 (void) duk_push_object_helper(ctx,
69131 DUK_HOBJECT_FLAG_EXTENSIBLE |
69132 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
69133 -1); /* no prototype, updated below */
69134
69135 duk_push_tval(ctx, DUK__REGP(bc));
69136 duk_to_object(ctx, -1);
69137 duk_dup(ctx, -1);
69138
69139 /* [ ... env target ] */
69140 /* [ ... env target target ] */
69141
69142 duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
69143 duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
69144
69145 /* [ ... env ] */
69146
69147 DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT",
69148 (duk_tval *) duk_get_tval(ctx, -1)));
69149 }
69150
69151 /* allocate catcher and populate it (should be atomic) */
69152
69153 duk_hthread_catchstack_grow(thr);
69154 cat = thr->catchstack + thr->catchstack_top;
69155 DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size);
69156 thr->catchstack_top++;
69157
69158 cat->flags = DUK_CAT_TYPE_TCF;
69159 cat->h_varname = NULL;
69160
69161 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
69162 cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
69163 }
69164 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
69165 cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
69166 }
69167 if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
69168 DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
69169 cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
69170 tv1 = DUK__REGP(bc);
69171 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
69172
69173 /* borrowed reference; although 'tv1' comes from a register,
69174 * its value was loaded using LDCONST so the constant will
69175 * also exist and be reachable.
69176 */
69177 cat->h_varname = DUK_TVAL_GET_STRING(tv1);
69178 } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
69179 /* env created above to stack top */
69180 duk_hobject *new_env;
69181
69182 DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher"));
69183 cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
69184
69185 DUK_DDD(DUK_DDDPRINT("activating object env: %!iT",
69186 (duk_tval *) duk_get_tval(ctx, -1)));
69187 new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
69188 DUK_ASSERT(new_env != NULL);
69189
69190 act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
69191 DUK_ASSERT(act->lex_env != NULL);
69192 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */
69193
69194 act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
69195 act->lex_env = new_env;
69196 DUK_HOBJECT_INCREF(thr, new_env);
69197 duk_pop(ctx);
69198 } else {
69199 ;
69200 }
69201
69202 /* Registers 'bc' and 'bc + 1' are written in longjmp handling
69203 * and if their previous values (which are temporaries) become
69204 * unreachable -and- have a finalizer, there'll be a function
69205 * call during error handling which is not supported now (GH-287).
69206 * Ensure that both 'bc' and 'bc + 1' have primitive values to
69207 * guarantee no finalizer calls in error handling. Scrubbing also
69208 * ensures finalizers for the previous values run here rather than
69209 * later. Error handling related values are also written to 'bc'
69210 * and 'bc + 1' but those values never become unreachable during
69211 * error handling, so there's no side effect problem even if the
69212 * error value has a finalizer.
69213 */
69214 duk_to_undefined(ctx, bc);
69215 duk_to_undefined(ctx, bc + 1);
69216
69217 cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */
69218 cat->callstack_index = thr->callstack_top - 1;
69219 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
69220 cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
69221
69222 DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
69223 "idx_base=%ld, h_varname=%!O",
69224 (unsigned long) cat->flags, (long) cat->callstack_index,
69225 (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
69226
69227 curr_pc += 2; /* skip jump slots */
69228 break;
69229 }
69230
69231 /* Pre/post inc/dec for register variables, important for loops. */
69232 case DUK_OP_PREINCR:
69233 case DUK_OP_PREDECR:
69234 case DUK_OP_POSTINCR:
69235 case DUK_OP_POSTDECR: {
69236 duk_context *ctx = (duk_context *) thr;
69237 duk_small_uint_fast_t a = DUK_DEC_A(ins);
69238 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69239 duk_tval *tv1, *tv2;
69240 duk_double_t x, y, z;
69241
69242 /* Two lowest bits of opcode are used to distinguish
69243 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69244 */
69245 DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
69246 DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
69247 DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
69248 DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
69249
69250 tv1 = DUK__REGP(bc);
69251#if defined(DUK_USE_FASTINT)
69252 if (DUK_TVAL_IS_FASTINT(tv1)) {
69253 duk_int64_t x_fi, y_fi, z_fi;
69254 x_fi = DUK_TVAL_GET_FASTINT(tv1);
69255 if (ins & DUK_ENC_OP(0x01)) {
69256 if (x_fi == DUK_FASTINT_MIN) {
69257 goto skip_fastint;
69258 }
69259 y_fi = x_fi - 1;
69260 } else {
69261 if (x_fi == DUK_FASTINT_MAX) {
69262 goto skip_fastint;
69263 }
69264 y_fi = x_fi + 1;
69265 }
69266
69267 DUK_TVAL_SET_FASTINT(tv1, y_fi); /* no need for refcount update */
69268
69269 tv2 = DUK__REGP(a);
69270 z_fi = (ins & DUK_ENC_OP(0x02)) ? x_fi : y_fi;
69271 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv2, z_fi); /* side effects */
69272 break;
69273 }
69274 skip_fastint:
69275#endif
69276 if (DUK_TVAL_IS_NUMBER(tv1)) {
69277 /* Fast path for the case where the register
69278 * is a number (e.g. loop counter).
69279 */
69280
69281 x = DUK_TVAL_GET_NUMBER(tv1);
69282 if (ins & DUK_ENC_OP(0x01)) {
69283 y = x - 1.0;
69284 } else {
69285 y = x + 1.0;
69286 }
69287
69288 DUK_TVAL_SET_NUMBER(tv1, y); /* no need for refcount update */
69289 } else {
69290 x = duk_to_number(ctx, bc);
69291
69292 if (ins & DUK_ENC_OP(0x01)) {
69293 y = x - 1.0;
69294 } else {
69295 y = x + 1.0;
69296 }
69297
69298 duk_push_number(ctx, y);
69299 duk_replace(ctx, bc);
69300 }
69301
69302 tv2 = DUK__REGP(a);
69303 z = (ins & DUK_ENC_OP(0x02)) ? x : y;
69304 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv2, z); /* side effects */
69305 break;
69306 }
69307
69308 /* Preinc/predec for var-by-name, slow path. */
69309 case DUK_OP_PREINCV:
69310 case DUK_OP_PREDECV:
69311 case DUK_OP_POSTINCV:
69312 case DUK_OP_POSTDECV: {
69313 duk_context *ctx = (duk_context *) thr;
69314 duk_activation *act;
69315 duk_small_uint_fast_t a = DUK_DEC_A(ins);
69316 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69317 duk_double_t x, y;
69318 duk_tval *tv1;
69319 duk_hstring *name;
69320
69321 /* Two lowest bits of opcode are used to distinguish
69322 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69323 */
69324 DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
69325 DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
69326 DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
69327 DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
69328
69329 tv1 = DUK__CONSTP(bc);
69330 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
69331 name = DUK_TVAL_GET_STRING(tv1);
69332 DUK_ASSERT(name != NULL);
69333 act = thr->callstack + thr->callstack_top - 1;
69334 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
69335
69336 /* XXX: fastint fast path would be very useful here */
69337
69338 x = duk_to_number(ctx, -2);
69339 duk_pop_2(ctx);
69340 if (ins & DUK_ENC_OP(0x01)) {
69341 y = x - 1.0;
69342 } else {
69343 y = x + 1.0;
69344 }
69345
69346 duk_push_number(ctx, y);
69347 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
69348 DUK_ASSERT(tv1 != NULL);
69349 act = thr->callstack + thr->callstack_top - 1;
69350 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
69351 duk_pop(ctx);
69352
69353 duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
69354 duk_replace(ctx, (duk_idx_t) a);
69355 break;
69356 }
69357
69358 /* Preinc/predec for object properties. */
69359 case DUK_OP_PREINCP:
69360 case DUK_OP_PREDECP:
69361 case DUK_OP_POSTINCP:
69362 case DUK_OP_POSTDECP: {
69363 duk_context *ctx = (duk_context *) thr;
69364 duk_small_uint_fast_t a = DUK_DEC_A(ins);
69365 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69366 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69367 duk_tval *tv_obj;
69368 duk_tval *tv_key;
69369 duk_tval *tv_val;
69370 duk_bool_t rc;
69371 duk_double_t x, y;
69372
69373 /* A -> target reg
69374 * B -> object reg/const (may be const e.g. in "'foo'[1]")
69375 * C -> key reg/const
69376 */
69377
69378 /* Two lowest bits of opcode are used to distinguish
69379 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69380 */
69381 DUK_ASSERT((DUK_OP_PREINCP & 0x03) == 0x00);
69382 DUK_ASSERT((DUK_OP_PREDECP & 0x03) == 0x01);
69383 DUK_ASSERT((DUK_OP_POSTINCP & 0x03) == 0x02);
69384 DUK_ASSERT((DUK_OP_POSTDECP & 0x03) == 0x03);
69385
69386 tv_obj = DUK__REGCONSTP(b);
69387 tv_key = DUK__REGCONSTP(c);
69388 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
69389 DUK_UNREF(rc); /* ignore */
69390 tv_obj = NULL; /* invalidated */
69391 tv_key = NULL; /* invalidated */
69392
69393 x = duk_to_number(ctx, -1);
69394 duk_pop(ctx);
69395 if (ins & DUK_ENC_OP(0x01)) {
69396 y = x - 1.0;
69397 } else {
69398 y = x + 1.0;
69399 }
69400
69401 duk_push_number(ctx, y);
69402 tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
69403 DUK_ASSERT(tv_val != NULL);
69404 tv_obj = DUK__REGCONSTP(b);
69405 tv_key = DUK__REGCONSTP(c);
69406 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
69407 DUK_UNREF(rc); /* ignore */
69408 tv_obj = NULL; /* invalidated */
69409 tv_key = NULL; /* invalidated */
69410 duk_pop(ctx);
69411
69412 duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
69413 duk_replace(ctx, (duk_idx_t) a);
69414 break;
69415 }
69416
69417 case DUK_OP_EXTRA: {
69418 /* XXX: shared decoding of 'b' and 'c'? */
69419
69420 duk_small_uint_fast_t extraop = DUK_DEC_A(ins);
69421 switch ((int) extraop) {
69422 /* XXX: switch cast? */
69423
69424 case DUK_EXTRAOP_NOP: {
69425 /* nop */
69426 break;
69427 }
69428
69429 case DUK_EXTRAOP_INVALID: {
69430 DUK_ERROR_FMT1(thr, DUK_ERR_INTERNAL_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_BC(ins));
69431 break;
69432 }
69433
69434 case DUK_EXTRAOP_LDTHIS: {
69435 /* Note: 'this' may be bound to any value, not just an object */
69436 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69437 duk_tval *tv1, *tv2;
69438
69439 tv1 = DUK__REGP(bc);
69440 tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */
69441 DUK_ASSERT(tv2 >= thr->valstack);
69442
69443 DUK_DDD(DUK_DDDPRINT("LDTHIS: %!T to r%ld", (duk_tval *) tv2, (long) bc));
69444
69445 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
69446 break;
69447 }
69448
69449 case DUK_EXTRAOP_LDUNDEF: {
69450 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69451 duk_tval *tv1;
69452
69453 tv1 = DUK__REGP(bc);
69454 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
69455 break;
69456 }
69457
69458 case DUK_EXTRAOP_LDNULL: {
69459 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69460 duk_tval *tv1;
69461
69462 tv1 = DUK__REGP(bc);
69463 DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */
69464 break;
69465 }
69466
69467 case DUK_EXTRAOP_LDTRUE:
69468 case DUK_EXTRAOP_LDFALSE: {
69469 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69470 duk_tval *tv1;
69471 duk_small_uint_fast_t bval = (extraop == DUK_EXTRAOP_LDTRUE ? 1 : 0);
69472
69473 tv1 = DUK__REGP(bc);
69474 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, bval); /* side effects */
69475 break;
69476 }
69477
69478 case DUK_EXTRAOP_NEWOBJ: {
69479 duk_context *ctx = (duk_context *) thr;
69480 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69481
69482 duk_push_object(ctx);
69483 duk_replace(ctx, (duk_idx_t) b);
69484 break;
69485 }
69486
69487 case DUK_EXTRAOP_NEWARR: {
69488 duk_context *ctx = (duk_context *) thr;
69489 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69490
69491 duk_push_array(ctx);
69492 duk_replace(ctx, (duk_idx_t) b);
69493 break;
69494 }
69495
69496 case DUK_EXTRAOP_SETALEN: {
69497 duk_small_uint_fast_t b;
69498 duk_small_uint_fast_t c;
69499 duk_tval *tv1;
69500 duk_hobject *h;
69501 duk_uint32_t len;
69502
69503 b = DUK_DEC_B(ins); tv1 = DUK__REGP(b);
69504 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
69505 h = DUK_TVAL_GET_OBJECT(tv1);
69506
69507 c = DUK_DEC_C(ins); tv1 = DUK__REGP(c);
69508 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
69509 len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
69510
69511 duk_hobject_set_length(thr, h, len);
69512
69513 break;
69514 }
69515
69516 case DUK_EXTRAOP_TYPEOF: {
69517 duk_context *ctx = (duk_context *) thr;
69518 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69519 duk_push_hstring(ctx, duk_js_typeof(thr, DUK__REGP(bc)));
69520 duk_replace(ctx, (duk_idx_t) bc);
69521 break;
69522 }
69523
69524 case DUK_EXTRAOP_TYPEOFID: {
69525 duk_context *ctx = (duk_context *) thr;
69526 duk_activation *act;
69527 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69528 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69529 duk_hstring *name;
69530 duk_tval *tv;
69531
69532 /* B -> target register
69533 * C -> constant index of identifier name
69534 */
69535
69536 tv = DUK__REGCONSTP(c); /* XXX: this could be a DUK__CONSTP instead */
69537 DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
69538 name = DUK_TVAL_GET_STRING(tv);
69539 act = thr->callstack + thr->callstack_top - 1;
69540 if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
69541 /* -> [... val this] */
69542 tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
69543 duk_push_hstring(ctx, duk_js_typeof(thr, tv));
69544 duk_replace(ctx, (duk_idx_t) b);
69545 duk_pop_2(ctx);
69546 } else {
69547 /* unresolvable, no stack changes */
69548 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
69549 duk_replace(ctx, (duk_idx_t) b);
69550 }
69551
69552 break;
69553 }
69554
69555 case DUK_EXTRAOP_INITENUM: {
69556 duk_context *ctx = (duk_context *) thr;
69557 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69558 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69559
69560 /*
69561 * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
69562 * If called with 'null' or 'undefined', this opcode returns 'null' as
69563 * the enumerator, which is special cased in NEXTENUM. This simplifies
69564 * the compiler part
69565 */
69566
69567 /* B -> register for writing enumerator object
69568 * C -> value to be enumerated (register)
69569 */
69570
69571 if (duk_is_null_or_undefined(ctx, (duk_idx_t) c)) {
69572 duk_push_null(ctx);
69573 duk_replace(ctx, (duk_idx_t) b);
69574 } else {
69575 duk_dup(ctx, (duk_idx_t) c);
69576 duk_to_object(ctx, -1);
69577 duk_hobject_enumerator_create(ctx, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
69578 duk_replace(ctx, (duk_idx_t) b);
69579 }
69580 break;
69581 }
69582
69583 case DUK_EXTRAOP_NEXTENUM: {
69584 duk_context *ctx = (duk_context *) thr;
69585 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69586 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69587
69588 /*
69589 * NEXTENUM checks whether the enumerator still has unenumerated
69590 * keys. If so, the next key is loaded to the target register
69591 * and the next instruction is skipped. Otherwise the next instruction
69592 * will be executed, jumping out of the enumeration loop.
69593 */
69594
69595 /* B -> target register for next key
69596 * C -> enum register
69597 */
69598
69599 DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
69600 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b),
69601 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) c)));
69602
69603 if (duk_is_object(ctx, (duk_idx_t) c)) {
69604 /* XXX: assert 'c' is an enumerator */
69605 duk_dup(ctx, (duk_idx_t) c);
69606 if (duk_hobject_enumerator_next(ctx, 0 /*get_value*/)) {
69607 /* [ ... enum ] -> [ ... next_key ] */
69608 DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
69609 (duk_tval *) duk_get_tval(ctx, -1)));
69610 curr_pc++;
69611 } else {
69612 /* [ ... enum ] -> [ ... ] */
69613 DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
69614 duk_push_undefined(ctx);
69615 }
69616 duk_replace(ctx, (duk_idx_t) b);
69617 } else {
69618 /* 'null' enumerator case -> behave as with an empty enumerator */
69619 DUK_ASSERT(duk_is_null(ctx, (duk_idx_t) c));
69620 DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
69621 }
69622 break;
69623 }
69624
69625 case DUK_EXTRAOP_INITSET:
69626 case DUK_EXTRAOP_INITSETI:
69627 case DUK_EXTRAOP_INITGET:
69628 case DUK_EXTRAOP_INITGETI: {
69629 duk_context *ctx = (duk_context *) thr;
69630 duk_bool_t is_set = (extraop == DUK_EXTRAOP_INITSET || extraop == DUK_EXTRAOP_INITSETI);
69631 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69632 duk_uint_fast_t idx;
69633
69634 /* B -> object register
69635 * C -> C+0 contains key, C+1 closure (value)
69636 */
69637
69638 /*
69639 * INITSET/INITGET are only used to initialize object literal keys.
69640 * The compiler ensures that there cannot be a previous data property
69641 * of the same name. It also ensures that setter and getter can only
69642 * be initialized once (or not at all).
69643 */
69644
69645 idx = (duk_uint_fast_t) DUK_DEC_C(ins);
69646 if (extraop == DUK_EXTRAOP_INITSETI || extraop == DUK_EXTRAOP_INITGETI) {
69647 duk_tval *tv_ind = DUK__REGP(idx);
69648 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
69649 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
69650 }
69651
69652#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
69653 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
69654 /* XXX: use duk_is_valid_index() instead? */
69655 /* XXX: improve check; check against nregs, not against top */
69656 DUK__INTERNAL_ERROR("INITSET/INITGET out of bounds");
69657 }
69658#endif
69659
69660 /* XXX: this is now a very unoptimal implementation -- this can be
69661 * made very simple by direct manipulation of the object internals,
69662 * given the guarantees above.
69663 */
69664
69665 duk_push_hobject_bidx(ctx, DUK_BIDX_OBJECT_CONSTRUCTOR);
69666 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_DEFINE_PROPERTY);
69667 duk_push_undefined(ctx);
69668 duk_dup(ctx, (duk_idx_t) b);
69669 duk_dup(ctx, (duk_idx_t) (idx + 0));
69670 duk_push_object(ctx); /* -> [ Object defineProperty undefined obj key desc ] */
69671
69672 duk_push_true(ctx);
69673 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
69674 duk_push_true(ctx);
69675 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
69676 duk_dup(ctx, (duk_idx_t) (idx + 1));
69677 duk_put_prop_stridx(ctx, -2, (is_set ? DUK_STRIDX_SET : DUK_STRIDX_GET));
69678
69679 DUK_DDD(DUK_DDDPRINT("INITGET/INITSET: obj=%!T, key=%!T, desc=%!T",
69680 (duk_tval *) duk_get_tval(ctx, -3),
69681 (duk_tval *) duk_get_tval(ctx, -2),
69682 (duk_tval *) duk_get_tval(ctx, -1)));
69683
69684 duk_call_method(ctx, 3); /* -> [ Object res ] */
69685 duk_pop_2(ctx);
69686
69687 DUK_DDD(DUK_DDDPRINT("INITGET/INITSET AFTER: obj=%!T",
69688 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b)));
69689 break;
69690 }
69691
69692 case DUK_EXTRAOP_ENDTRY: {
69693 duk_catcher *cat;
69694 duk_tval *tv1;
69695
69696 DUK_ASSERT(thr->catchstack_top >= 1);
69697 DUK_ASSERT(thr->callstack_top >= 1);
69698 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
69699
69700 cat = thr->catchstack + thr->catchstack_top - 1;
69701
69702 DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
69703 DUK_CAT_CLEAR_CATCH_ENABLED(cat);
69704
69705 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
69706 DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
69707
69708 tv1 = thr->valstack + cat->idx_base;
69709 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
69710 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
69711 tv1 = NULL;
69712
69713 tv1 = thr->valstack + cat->idx_base + 1;
69714 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
69715 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
69716 tv1 = NULL;
69717
69718 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
69719 } else {
69720 DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
69721 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69722 /* no need to unwind callstack */
69723 }
69724
69725 curr_pc = cat->pc_base + 1;
69726 break;
69727 }
69728
69729 case DUK_EXTRAOP_ENDCATCH: {
69730 duk_activation *act;
69731 duk_catcher *cat;
69732 duk_tval *tv1;
69733
69734 DUK_ASSERT(thr->catchstack_top >= 1);
69735 DUK_ASSERT(thr->callstack_top >= 1);
69736 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
69737
69738 cat = thr->catchstack + thr->catchstack_top - 1;
69739 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
69740
69741 act = thr->callstack + thr->callstack_top - 1;
69742
69743 if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
69744 duk_hobject *prev_env;
69745
69746 /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
69747 DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
69748 DUK_ASSERT(act->lex_env != NULL);
69749
69750 DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
69751
69752 prev_env = act->lex_env;
69753 DUK_ASSERT(prev_env != NULL);
69754 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
69755 DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
69756 DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
69757 }
69758
69759 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
69760 DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
69761
69762 tv1 = thr->valstack + cat->idx_base;
69763 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
69764 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
69765 tv1 = NULL;
69766
69767 tv1 = thr->valstack + cat->idx_base + 1;
69768 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
69769 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
69770 tv1 = NULL;
69771
69772 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
69773 } else {
69774 DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
69775 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69776 /* no need to unwind callstack */
69777 }
69778
69779 curr_pc = cat->pc_base + 1;
69780 break;
69781 }
69782
69783 case DUK_EXTRAOP_ENDFIN: {
69784 duk_context *ctx = (duk_context *) thr;
69785 duk_catcher *cat;
69786 duk_tval *tv1;
69787 duk_small_uint_t cont_type;
69788 duk_small_uint_t ret_result;
69789
69790 /* Sync and NULL early. */
69791 DUK__SYNC_AND_NULL_CURR_PC();
69792
69793 DUK_ASSERT(thr->catchstack_top >= 1);
69794 DUK_ASSERT(thr->callstack_top >= 1);
69795 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
69796
69797 cat = thr->catchstack + thr->catchstack_top - 1;
69798
69799 /* CATCH flag may be enabled or disabled here; it may be enabled if
69800 * the statement has a catch block but the try block does not throw
69801 * an error.
69802 */
69803 DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
69804 /* XXX: assert idx_base */
69805
69806 DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
69807 (duk_tval *) (thr->valstack + cat->idx_base + 0),
69808 (duk_tval *) (thr->valstack + cat->idx_base + 1)));
69809
69810 tv1 = thr->valstack + cat->idx_base + 1; /* type */
69811 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
69812 cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
69813
69814 switch (cont_type) {
69815 case DUK_LJ_TYPE_NORMAL: {
69816 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
69817 "dismantle catcher, resume execution after ENDFIN"));
69818 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69819 /* no need to unwind callstack */
69820 goto restart_execution;
69821 }
69822 case DUK_LJ_TYPE_RETURN: {
69823 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
69824 "catcher, handle return, lj.value1=%!T", thr->valstack + cat->idx_base));
69825
69826 /* Not necessary to unwind catchstack: return handling will
69827 * do it. The finally flag of 'cat' is no longer set. The
69828 * catch flag may be set, but it's not checked by return handling.
69829 */
69830 DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
69831#if 0
69832 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69833#endif
69834
69835 duk_push_tval(ctx, thr->valstack + cat->idx_base);
69836 ret_result = duk__handle_return(thr,
69837 entry_thread,
69838 entry_callstack_top);
69839 if (ret_result == DUK__RETHAND_RESTART) {
69840 goto restart_execution;
69841 }
69842 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
69843
69844 DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
69845 return;
69846 }
69847 case DUK_LJ_TYPE_BREAK:
69848 case DUK_LJ_TYPE_CONTINUE: {
69849 duk_uint_t label_id;
69850 duk_small_uint_t lj_type;
69851
69852 /* Not necessary to unwind catchstack: break/continue
69853 * handling will do it. The finally flag of 'cat' is
69854 * no longer set. The catch flag may be set, but it's
69855 * not checked by break/continue handling.
69856 */
69857#if 0
69858 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69859#endif
69860
69861 tv1 = thr->valstack + cat->idx_base;
69862 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
69863#if defined(DUK_USE_FASTINT)
69864 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
69865 label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
69866#else
69867 label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
69868#endif
69869 lj_type = cont_type;
69870 duk__handle_break_or_continue(thr, label_id, lj_type);
69871 goto restart_execution;
69872 }
69873 default: {
69874 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
69875 "dismantle catcher, re-throw error",
69876 (long) cont_type));
69877
69878 duk_push_tval(ctx, thr->valstack + cat->idx_base);
69879
69880 duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
69881
69882 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
69883 duk_err_longjmp(thr);
69884 DUK_UNREACHABLE();
69885 }
69886 }
69887
69888 /* Must restart in all cases because we NULLed thr->ptr_curr_pc. */
69889 DUK_UNREACHABLE();
69890 break;
69891 }
69892
69893 case DUK_EXTRAOP_THROW: {
69894 duk_context *ctx = (duk_context *) thr;
69895 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69896
69897 /* Note: errors are augmented when they are created, not
69898 * when they are thrown. So, don't augment here, it would
69899 * break re-throwing for instance.
69900 */
69901
69902 /* Sync so that augmentation sees up-to-date activations, NULL
69903 * thr->ptr_curr_pc so that it's not used if side effects occur
69904 * in augmentation or longjmp handling.
69905 */
69906 DUK__SYNC_AND_NULL_CURR_PC();
69907
69908 duk_dup(ctx, (duk_idx_t) bc);
69909 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
69910 (duk_tval *) duk_get_tval(ctx, -1)));
69911#if defined(DUK_USE_AUGMENT_ERROR_THROW)
69912 duk_err_augment_error_throw(thr);
69913 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
69914 (duk_tval *) duk_get_tval(ctx, -1)));
69915#endif
69916
69917 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
69918
69919 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
69920 duk_err_longjmp(thr);
69921 DUK_UNREACHABLE();
69922 break;
69923 }
69924
69925 case DUK_EXTRAOP_INVLHS: {
69926 DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "invalid lvalue");
69927
69928 DUK_UNREACHABLE();
69929 break;
69930 }
69931
69932 case DUK_EXTRAOP_UNM:
69933 case DUK_EXTRAOP_UNP: {
69934 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69935 duk__vm_arith_unary_op(thr, DUK__REGP(bc), bc, extraop);
69936 break;
69937 }
69938
69939 case DUK_EXTRAOP_DEBUGGER: {
69940 /* Opcode only emitted by compiler when debugger
69941 * support is enabled. Ignore it silently without
69942 * debugger support, in case it has been loaded
69943 * from precompiled bytecode.
69944 */
69945#if defined(DUK_USE_DEBUGGER_SUPPORT)
69946 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
69947 DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
69948 DUK__SYNC_AND_NULL_CURR_PC();
69949 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
69950 DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
69951 goto restart_execution;
69952 } else {
69953 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
69954 }
69955#else
69956 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
69957#endif
69958 break;
69959 }
69960
69961 case DUK_EXTRAOP_BREAK: {
69962 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69963
69964 DUK_DDD(DUK_DDDPRINT("BREAK: %ld", (long) bc));
69965
69966 DUK__SYNC_AND_NULL_CURR_PC();
69967 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
69968 goto restart_execution;
69969 }
69970
69971 case DUK_EXTRAOP_CONTINUE: {
69972 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69973
69974 DUK_DDD(DUK_DDDPRINT("CONTINUE: %ld", (long) bc));
69975
69976 DUK__SYNC_AND_NULL_CURR_PC();
69977 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
69978 goto restart_execution;
69979 }
69980
69981 case DUK_EXTRAOP_BNOT: {
69982 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69983
69984 duk__vm_bitwise_not(thr, DUK__REGP(bc), bc);
69985 break;
69986 }
69987
69988 case DUK_EXTRAOP_LNOT: {
69989 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69990 duk_tval *tv1;
69991
69992 tv1 = DUK__REGP(bc);
69993 duk__vm_logical_not(thr, tv1, tv1);
69994 break;
69995 }
69996
69997 case DUK_EXTRAOP_INSTOF: {
69998 duk_context *ctx = (duk_context *) thr;
69999 duk_small_uint_fast_t b = DUK_DEC_B(ins);
70000 duk_small_uint_fast_t c = DUK_DEC_C(ins);
70001 duk_bool_t tmp;
70002
70003 tmp = duk_js_instanceof(thr, DUK__REGP(b), DUK__REGCONSTP(c));
70004 duk_push_boolean(ctx, tmp);
70005 duk_replace(ctx, (duk_idx_t) b);
70006 break;
70007 }
70008
70009 case DUK_EXTRAOP_IN: {
70010 duk_context *ctx = (duk_context *) thr;
70011 duk_small_uint_fast_t b = DUK_DEC_B(ins);
70012 duk_small_uint_fast_t c = DUK_DEC_C(ins);
70013 duk_bool_t tmp;
70014
70015 tmp = duk_js_in(thr, DUK__REGP(b), DUK__REGCONSTP(c));
70016 duk_push_boolean(ctx, tmp);
70017 duk_replace(ctx, (duk_idx_t) b);
70018 break;
70019 }
70020
70021 case DUK_EXTRAOP_LABEL: {
70022 duk_catcher *cat;
70023 duk_uint_fast_t bc = DUK_DEC_BC(ins);
70024
70025 /* allocate catcher and populate it (should be atomic) */
70026
70027 duk_hthread_catchstack_grow(thr);
70028 cat = thr->catchstack + thr->catchstack_top;
70029 thr->catchstack_top++;
70030
70031 cat->flags = DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT);
70032 cat->callstack_index = thr->callstack_top - 1;
70033 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
70034 cat->idx_base = 0; /* unused for label */
70035 cat->h_varname = NULL;
70036
70037 DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
70038 "idx_base=%ld, h_varname=%!O, label_id=%ld",
70039 (long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base,
70040 (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
70041
70042 curr_pc += 2; /* skip jump slots */
70043 break;
70044 }
70045
70046 case DUK_EXTRAOP_ENDLABEL: {
70047 duk_catcher *cat;
70048#if defined(DUK_USE_DDDPRINT) || defined(DUK_USE_ASSERTIONS)
70049 duk_uint_fast_t bc = DUK_DEC_BC(ins);
70050#endif
70051#if defined(DUK_USE_DDDPRINT)
70052 DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
70053#endif
70054
70055 DUK_ASSERT(thr->catchstack_top >= 1);
70056
70057 cat = thr->catchstack + thr->catchstack_top - 1;
70058 DUK_UNREF(cat);
70059 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
70060 DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(cat) == bc);
70061
70062 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
70063 /* no need to unwind callstack */
70064 break;
70065 }
70066
70067 default: {
70068 DUK__INTERNAL_ERROR("invalid extra opcode");
70069 }
70070
70071 } /* end switch */
70072
70073 break;
70074 }
70075
70076 default: {
70077 /* this should never be possible, because the switch-case is
70078 * comprehensive
70079 */
70080 DUK__INTERNAL_ERROR("invalid opcode");
70081 break;
70082 }
70083
70084 } /* end switch */
70085 }
70086 DUK_UNREACHABLE();
70087
70088#ifndef DUK_USE_VERBOSE_EXECUTOR_ERRORS
70089 internal_error:
70090 DUK_ERROR_INTERNAL(thr, "internal error in bytecode executor");
70091#endif
70092}
70093
70094#undef DUK__LONGJMP_RESTART
70095#undef DUK__LONGJMP_FINISHED
70096#undef DUK__LONGJMP_RETHROW
70097
70098#undef DUK__RETHAND_RESTART
70099#undef DUK__RETHAND_FINISHED
70100
70101#undef DUK__FUN
70102#undef DUK__STRICT
70103#undef DUK__REG
70104#undef DUK__REGP
70105#undef DUK__CONST
70106#undef DUK__CONSTP
70107#undef DUK__RCISREG
70108#undef DUK__REGCONST
70109#undef DUK__REGCONSTP
70110
70111#undef DUK__INTERNAL_ERROR
70112#undef DUK__SYNC_CURR_PC
70113#undef DUK__SYNC_AND_NULL_CURR_PC
70114#line 1 "duk_js_ops.c"
70115/*
70116 * Ecmascript specification algorithm and conversion helpers.
70117 *
70118 * These helpers encapsulate the primitive Ecmascript operation
70119 * semantics, and are used by the bytecode executor and the API
70120 * (among other places). Note that some primitives are only
70121 * implemented as part of the API and have no "internal" helper.
70122 * (This is the case when an internal helper would not really be
70123 * useful; e.g. the operation is rare, uses value stack heavily,
70124 * etc.)
70125 *
70126 * The operation arguments depend on what is required to implement
70127 * the operation:
70128 *
70129 * - If an operation is simple and stateless, and has no side
70130 * effects, it won't take an duk_hthread argument and its
70131 * arguments may be duk_tval pointers (which are safe as long
70132 * as no side effects take place).
70133 *
70134 * - If complex coercions are required (e.g. a "ToNumber" coercion)
70135 * or errors may be thrown, the operation takes an duk_hthread
70136 * argument. This also implies that the operation may have
70137 * arbitrary side effects, invalidating any duk_tval pointers.
70138 *
70139 * - For operations with potential side effects, arguments can be
70140 * taken in several ways:
70141 *
70142 * a) as duk_tval pointers, which makes sense if the "common case"
70143 * can be resolved without side effects (e.g. coercion); the
70144 * arguments are pushed to the valstack for coercion if
70145 * necessary
70146 *
70147 * b) as duk_tval values
70148 *
70149 * c) implicitly on value stack top
70150 *
70151 * d) as indices to the value stack
70152 *
70153 * Future work:
70154 *
70155 * - Argument styles may not be the most sensible in every case now.
70156 *
70157 * - In-place coercions might be useful for several operations, if
70158 * in-place coercion is OK for the bytecode executor and the API.
70159 */
70160
70161/* include removed: duk_internal.h */
70162
70163/*
70164 * [[DefaultValue]] (E5 Section 8.12.8)
70165 *
70166 * ==> implemented in the API.
70167 */
70168
70169/*
70170 * ToPrimitive() (E5 Section 9.1)
70171 *
70172 * ==> implemented in the API.
70173 */
70174
70175/*
70176 * ToBoolean() (E5 Section 9.2)
70177 */
70178
70179DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
70180 switch (DUK_TVAL_GET_TAG(tv)) {
70181 case DUK_TAG_UNDEFINED:
70182 case DUK_TAG_NULL:
70183 return 0;
70184 case DUK_TAG_BOOLEAN:
70185 return DUK_TVAL_GET_BOOLEAN(tv);
70186 case DUK_TAG_STRING: {
70187 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
70188 DUK_ASSERT(h != NULL);
70189 return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
70190 }
70191 case DUK_TAG_OBJECT: {
70192 return 1;
70193 }
70194 case DUK_TAG_BUFFER: {
70195 /* mimic semantics for strings */
70196 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
70197 DUK_ASSERT(h != NULL);
70198 return (DUK_HBUFFER_GET_SIZE(h) > 0 ? 1 : 0);
70199 }
70200 case DUK_TAG_POINTER: {
70201 void *p = DUK_TVAL_GET_POINTER(tv);
70202 return (p != NULL ? 1 : 0);
70203 }
70204 case DUK_TAG_LIGHTFUNC: {
70205 return 1;
70206 }
70207#if defined(DUK_USE_FASTINT)
70208 case DUK_TAG_FASTINT:
70209 if (DUK_TVAL_GET_FASTINT(tv) != 0) {
70210 return 1;
70211 } else {
70212 return 0;
70213 }
70214#endif
70215 default: {
70216 /* number */
70217 duk_double_t d;
70218 int c;
70219 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
70220 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
70221 d = DUK_TVAL_GET_DOUBLE(tv);
70222 c = DUK_FPCLASSIFY((double) d);
70223 if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
70224 return 0;
70225 } else {
70226 return 1;
70227 }
70228 }
70229 }
70230 DUK_UNREACHABLE();
70231}
70232
70233/*
70234 * ToNumber() (E5 Section 9.3)
70235 *
70236 * Value to convert must be on stack top, and is popped before exit.
70237 *
70238 * See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
70239 * http://www.cs.indiana.edu/~burger/fp/index.html
70240 *
70241 * Notes on the conversion:
70242 *
70243 * - There are specific requirements on the accuracy of the conversion
70244 * through a "Mathematical Value" (MV), so this conversion is not
70245 * trivial.
70246 *
70247 * - Quick rejects (e.g. based on first char) are difficult because
70248 * the grammar allows leading and trailing white space.
70249 *
70250 * - Quick reject based on string length is difficult even after
70251 * accounting for white space; there may be arbitrarily many
70252 * decimal digits.
70253 *
70254 * - Standard grammar allows decimal values ("123"), hex values
70255 * ("0x123") and infinities
70256 *
70257 * - Unlike source code literals, ToNumber() coerces empty strings
70258 * and strings with only whitespace to zero (not NaN).
70259 */
70260
70261/* E5 Section 9.3.1 */
70262DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
70263 duk_context *ctx = (duk_context *) thr;
70264 duk_small_uint_t s2n_flags;
70265 duk_double_t d;
70266
70267 /* Quite lenient, e.g. allow empty as zero, but don't allow trailing
70268 * garbage.
70269 */
70270 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
70271 DUK_S2N_FLAG_ALLOW_EXP |
70272 DUK_S2N_FLAG_ALLOW_PLUS |
70273 DUK_S2N_FLAG_ALLOW_MINUS |
70274 DUK_S2N_FLAG_ALLOW_INF |
70275 DUK_S2N_FLAG_ALLOW_FRAC |
70276 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
70277 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
70278 DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
70279 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
70280 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
70281
70282 duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
70283 d = duk_get_number(ctx, -1);
70284 duk_pop(ctx);
70285
70286 return d;
70287}
70288
70289DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
70290 duk_context *ctx = (duk_hthread *) thr;
70291
70292 DUK_ASSERT(thr != NULL);
70293 DUK_ASSERT(tv != NULL);
70294
70295 switch (DUK_TVAL_GET_TAG(tv)) {
70296 case DUK_TAG_UNDEFINED: {
70297 /* return a specific NaN (although not strictly necessary) */
70298 duk_double_union du;
70299 DUK_DBLUNION_SET_NAN(&du);
70300 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
70301 return du.d;
70302 }
70303 case DUK_TAG_NULL: {
70304 /* +0.0 */
70305 return 0.0;
70306 }
70307 case DUK_TAG_BOOLEAN: {
70308 if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
70309 return 1.0;
70310 }
70311 return 0.0;
70312 }
70313 case DUK_TAG_STRING: {
70314 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
70315 duk_push_hstring(ctx, h);
70316 return duk__tonumber_string_raw(thr);
70317 }
70318 case DUK_TAG_OBJECT: {
70319 /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint),
70320 * so use [[DefaultValue]] directly.
70321 */
70322 duk_double_t d;
70323 duk_push_tval(ctx, tv);
70324 duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
70325
70326 /* recursive call for a primitive value (guaranteed not to cause second
70327 * recursion).
70328 */
70329 d = duk_js_tonumber(thr, duk_require_tval(ctx, -1));
70330
70331 duk_pop(ctx);
70332 return d;
70333 }
70334 case DUK_TAG_BUFFER: {
70335 /* Coerce like a string. This makes sense because addition also treats
70336 * buffers like strings.
70337 */
70338 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
70339 duk_push_hbuffer(ctx, h);
70340 duk_to_string(ctx, -1); /* XXX: expensive, but numconv now expects to see a string */
70341 return duk__tonumber_string_raw(thr);
70342 }
70343 case DUK_TAG_POINTER: {
70344 /* Coerce like boolean */
70345 void *p = DUK_TVAL_GET_POINTER(tv);
70346 return (p != NULL ? 1.0 : 0.0);
70347 }
70348 case DUK_TAG_LIGHTFUNC: {
70349 /* +(function(){}) -> NaN */
70350 return DUK_DOUBLE_NAN;
70351 }
70352#if defined(DUK_USE_FASTINT)
70353 case DUK_TAG_FASTINT:
70354 return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
70355#endif
70356 default: {
70357 /* number */
70358 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
70359 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
70360 return DUK_TVAL_GET_DOUBLE(tv);
70361 }
70362 }
70363
70364 DUK_UNREACHABLE();
70365}
70366
70367/*
70368 * ToInteger() (E5 Section 9.4)
70369 */
70370
70371/* exposed, used by e.g. duk_bi_date.c */
70372DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
70373 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
70374
70375 if (c == DUK_FP_NAN) {
70376 return 0.0;
70377 } else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
70378 /* XXX: FP_ZERO check can be removed, the else clause handles it
70379 * correctly (preserving sign).
70380 */
70381 return x;
70382 } else {
70383 duk_small_int_t s = (duk_small_int_t) DUK_SIGNBIT(x);
70384 x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
70385 if (s) {
70386 x = -x;
70387 }
70388 return x;
70389 }
70390}
70391
70392DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
70393 /* XXX: fastint */
70394 duk_double_t d = duk_js_tonumber(thr, tv); /* invalidates tv */
70395 return duk_js_tointeger_number(d);
70396}
70397
70398/*
70399 * ToInt32(), ToUint32(), ToUint16() (E5 Sections 9.5, 9.6, 9.7)
70400 */
70401
70402/* combined algorithm matching E5 Sections 9.5 and 9.6 */
70403DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
70404 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
70405 duk_small_int_t s;
70406
70407 if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
70408 return 0.0;
70409 }
70410
70411
70412 /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
70413 s = (duk_small_int_t) DUK_SIGNBIT(x);
70414 x = DUK_FLOOR(DUK_FABS(x));
70415 if (s) {
70416 x = -x;
70417 }
70418
70419 /* NOTE: fmod(x) result sign is same as sign of x, which
70420 * differs from what Javascript wants (see Section 9.6).
70421 */
70422
70423 x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */
70424
70425 if (x < 0.0) {
70426 x += DUK_DOUBLE_2TO32;
70427 }
70428 /* -> x in [0, 2**32[ */
70429
70430 if (is_toint32) {
70431 if (x >= DUK_DOUBLE_2TO31) {
70432 /* x in [2**31, 2**32[ */
70433
70434 x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */
70435 }
70436 }
70437
70438 return x;
70439}
70440
70441DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
70442 duk_double_t d;
70443
70444#if defined(DUK_USE_FASTINT)
70445 if (DUK_TVAL_IS_FASTINT(tv)) {
70446 return DUK_TVAL_GET_FASTINT_I32(tv);
70447 }
70448#endif
70449
70450 d = duk_js_tonumber(thr, tv); /* invalidates tv */
70451 d = duk__toint32_touint32_helper(d, 1);
70452 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
70453 DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */
70454 DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */
70455 return (duk_int32_t) d;
70456}
70457
70458
70459DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
70460 duk_double_t d;
70461
70462#if defined(DUK_USE_FASTINT)
70463 if (DUK_TVAL_IS_FASTINT(tv)) {
70464 return DUK_TVAL_GET_FASTINT_U32(tv);
70465 }
70466#endif
70467
70468 d = duk_js_tonumber(thr, tv); /* invalidates tv */
70469 d = duk__toint32_touint32_helper(d, 0);
70470 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
70471 DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); /* [0x00000000, 0xffffffff] */
70472 DUK_ASSERT(d == ((duk_double_t) ((duk_uint32_t) d))); /* whole, won't clip */
70473 return (duk_uint32_t) d;
70474
70475}
70476
70477DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
70478 /* should be a safe way to compute this */
70479 return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
70480}
70481
70482/*
70483 * ToString() (E5 Section 9.8)
70484 *
70485 * ==> implemented in the API.
70486 */
70487
70488/*
70489 * ToObject() (E5 Section 9.9)
70490 *
70491 * ==> implemented in the API.
70492 */
70493
70494/*
70495 * CheckObjectCoercible() (E5 Section 9.10)
70496 *
70497 * Note: no API equivalent now.
70498 */
70499
70500#if 0 /* unused */
70501DUK_INTERNAL void duk_js_checkobjectcoercible(duk_hthread *thr, duk_tval *tv_x) {
70502 duk_small_uint_t tag = DUK_TVAL_GET_TAG(tv_x);
70503
70504 /* Note: this must match ToObject() behavior */
70505
70506 if (tag == DUK_TAG_UNDEFINED ||
70507 tag == DUK_TAG_NULL ||
70508 tag == DUK_TAG_POINTER ||
70509 tag == DUK_TAG_BUFFER) {
70510 DUK_ERROR_TYPE(thr, "not object coercible");
70511 }
70512}
70513#endif
70514
70515/*
70516 * IsCallable() (E5 Section 9.11)
70517 *
70518 * XXX: API equivalent is a separate implementation now, and this has
70519 * currently no callers.
70520 */
70521
70522#if 0 /* unused */
70523DUK_INTERNAL duk_bool_t duk_js_iscallable(duk_tval *tv_x) {
70524 duk_hobject *obj;
70525
70526 if (!DUK_TVAL_IS_OBJECT(tv_x)) {
70527 return 0;
70528 }
70529 obj = DUK_TVAL_GET_OBJECT(tv_x);
70530 DUK_ASSERT(obj != NULL);
70531
70532 return DUK_HOBJECT_IS_CALLABLE(obj);
70533}
70534#endif
70535
70536/*
70537 * Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
70538 * 9.12). These have much in common so they can share some helpers.
70539 *
70540 * Future work notes:
70541 *
70542 * - Current implementation (and spec definition) has recursion; this should
70543 * be fixed if possible.
70544 *
70545 * - String-to-number coercion should be possible without going through the
70546 * value stack (and be more compact) if a shared helper is invoked.
70547 */
70548
70549/* Note that this is the same operation for strict and loose equality:
70550 * - E5 Section 11.9.3, step 1.c (loose)
70551 * - E5 Section 11.9.6, step 4 (strict)
70552 */
70553
70554DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) {
70555#if defined(DUK_USE_PARANOID_MATH)
70556 /* Straightforward algorithm, makes fewer compiler assumptions. */
70557 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
70558 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
70559 if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
70560 return 0;
70561 }
70562 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
70563 return 1;
70564 }
70565 if (x == y) {
70566 return 1;
70567 }
70568 return 0;
70569#else /* DUK_USE_PARANOID_MATH */
70570 /* Better equivalent algorithm. If the compiler is compliant, C and
70571 * Ecmascript semantics are identical for this particular comparison.
70572 * In particular, NaNs must never compare equal and zeroes must compare
70573 * equal regardless of sign. Could also use a macro, but this inlines
70574 * already nicely (no difference on gcc, for instance).
70575 */
70576 if (x == y) {
70577 /* IEEE requires that NaNs compare false */
70578 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
70579 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
70580 return 1;
70581 } else {
70582 /* IEEE requires that zeros compare the same regardless
70583 * of their signed, so if both x and y are zeroes, they
70584 * are caught above.
70585 */
70586 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
70587 return 0;
70588 }
70589#endif /* DUK_USE_PARANOID_MATH */
70590}
70591
70592DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
70593#if defined(DUK_USE_PARANOID_MATH)
70594 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
70595 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
70596
70597 if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
70598 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
70599 return 1;
70600 }
70601 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
70602 /* Note: cannot assume that a non-zero return value of signbit() would
70603 * always be the same -- hence cannot (portably) use something like:
70604 *
70605 * signbit(x) == signbit(y)
70606 */
70607 duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
70608 duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
70609 return (sx == sy);
70610 }
70611
70612 /* normal comparison; known:
70613 * - both x and y are not NaNs (but one of them can be)
70614 * - both x and y are not zero (but one of them can be)
70615 * - x and y may be denormal or infinite
70616 */
70617
70618 return (x == y);
70619#else /* DUK_USE_PARANOID_MATH */
70620 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
70621 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
70622
70623 if (x == y) {
70624 /* IEEE requires that NaNs compare false */
70625 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
70626 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
70627
70628 /* Using classification has smaller footprint than direct comparison. */
70629 if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
70630 /* Note: cannot assume that a non-zero return value of signbit() would
70631 * always be the same -- hence cannot (portably) use something like:
70632 *
70633 * signbit(x) == signbit(y)
70634 */
70635 duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
70636 duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
70637 return (sx == sy);
70638 }
70639 return 1;
70640 } else {
70641 /* IEEE requires that zeros compare the same regardless
70642 * of their signed, so if both x and y are zeroes, they
70643 * are caught above.
70644 */
70645 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
70646
70647 /* Difference to non-strict/strict comparison is that NaNs compare
70648 * equal and signed zero signs matter.
70649 */
70650 if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
70651 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
70652 return 1;
70653 }
70654 return 0;
70655 }
70656#endif /* DUK_USE_PARANOID_MATH */
70657}
70658
70659DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
70660 duk_context *ctx = (duk_context *) thr;
70661 duk_tval *tv_tmp;
70662
70663 /* If flags != 0 (strict or SameValue), thr can be NULL. For loose
70664 * equals comparison it must be != NULL.
70665 */
70666 DUK_ASSERT(flags != 0 || thr != NULL);
70667
70668 /*
70669 * Same type?
70670 *
70671 * Note: since number values have no explicit tag in the 8-byte
70672 * representation, need the awkward if + switch.
70673 */
70674
70675#if defined(DUK_USE_FASTINT)
70676 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
70677 if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
70678 return 1;
70679 } else {
70680 return 0;
70681 }
70682 }
70683 else
70684#endif
70685 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
70686 /* Catches both doubles and cases where only one argument is a fastint */
70687 if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
70688 /* SameValue */
70689 return duk__js_samevalue_number(DUK_TVAL_GET_NUMBER(tv_x),
70690 DUK_TVAL_GET_NUMBER(tv_y));
70691 } else {
70692 /* equals and strict equals */
70693 return duk__js_equals_number(DUK_TVAL_GET_NUMBER(tv_x),
70694 DUK_TVAL_GET_NUMBER(tv_y));
70695 }
70696 } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
70697 switch (DUK_TVAL_GET_TAG(tv_x)) {
70698 case DUK_TAG_UNDEFINED:
70699 case DUK_TAG_NULL: {
70700 return 1;
70701 }
70702 case DUK_TAG_BOOLEAN: {
70703 return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
70704 }
70705 case DUK_TAG_POINTER: {
70706 return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
70707 }
70708 case DUK_TAG_STRING:
70709 case DUK_TAG_OBJECT: {
70710 /* heap pointer comparison suffices */
70711 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
70712 }
70713 case DUK_TAG_BUFFER: {
70714 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
70715 /* heap pointer comparison suffices */
70716 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
70717 } else {
70718 /* non-strict equality for buffers compares contents */
70719 duk_hbuffer *h_x = DUK_TVAL_GET_BUFFER(tv_x);
70720 duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
70721 duk_size_t len_x = DUK_HBUFFER_GET_SIZE(h_x);
70722 duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
70723 void *buf_x;
70724 void *buf_y;
70725 if (len_x != len_y) {
70726 return 0;
70727 }
70728 buf_x = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_x);
70729 buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
70730 /* if len_x == len_y == 0, buf_x and/or buf_y may
70731 * be NULL, but that's OK.
70732 */
70733 DUK_ASSERT(len_x == len_y);
70734 DUK_ASSERT(len_x == 0 || buf_x != NULL);
70735 DUK_ASSERT(len_y == 0 || buf_y != NULL);
70736 return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
70737 }
70738 }
70739 case DUK_TAG_LIGHTFUNC: {
70740 /* At least 'magic' has a significant impact on function
70741 * identity.
70742 */
70743 duk_small_uint_t lf_flags_x;
70744 duk_small_uint_t lf_flags_y;
70745 duk_c_function func_x;
70746 duk_c_function func_y;
70747
70748 DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
70749 DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
70750 return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
70751 }
70752#if defined(DUK_USE_FASTINT)
70753 case DUK_TAG_FASTINT:
70754#endif
70755 default: {
70756 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
70757 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y));
70758 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
70759 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
70760 DUK_UNREACHABLE();
70761 return 0;
70762 }
70763 }
70764 }
70765
70766 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
70767 return 0;
70768 }
70769
70770 DUK_ASSERT(flags == 0); /* non-strict equality from here on */
70771
70772 /*
70773 * Types are different; various cases for non-strict comparison
70774 *
70775 * Since comparison is symmetric, we use a "swap trick" to reduce
70776 * code size.
70777 */
70778
70779 /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
70780 if ((DUK_TVAL_IS_UNDEFINED(tv_x) && DUK_TVAL_IS_NULL(tv_y)) ||
70781 (DUK_TVAL_IS_NULL(tv_x) && DUK_TVAL_IS_UNDEFINED(tv_y))) {
70782 return 1;
70783 }
70784
70785 /* Number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
70786 if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
70787 /* the next 'if' is guaranteed to match after swap */
70788 tv_tmp = tv_x;
70789 tv_x = tv_y;
70790 tv_y = tv_tmp;
70791 }
70792 if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
70793 /* XXX: this is possible without resorting to the value stack */
70794 duk_double_t d1, d2;
70795 d2 = DUK_TVAL_GET_NUMBER(tv_y);
70796 duk_push_tval(ctx, tv_x);
70797 duk_to_string(ctx, -1); /* buffer values are coerced first to string here */
70798 duk_to_number(ctx, -1);
70799 d1 = duk_require_number(ctx, -1);
70800 duk_pop(ctx);
70801 return duk__js_equals_number(d1, d2);
70802 }
70803
70804 /* Buffer/string -> compare contents. */
70805 if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
70806 tv_tmp = tv_x;
70807 tv_x = tv_y;
70808 tv_y = tv_tmp;
70809 }
70810 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
70811 duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
70812 duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
70813 duk_size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
70814 duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
70815 const void *buf_x;
70816 const void *buf_y;
70817 if (len_x != len_y) {
70818 return 0;
70819 }
70820 buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x);
70821 buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
70822 /* if len_x == len_y == 0, buf_x and/or buf_y may
70823 * be NULL, but that's OK.
70824 */
70825 DUK_ASSERT(len_x == len_y);
70826 DUK_ASSERT(len_x == 0 || buf_x != NULL);
70827 DUK_ASSERT(len_y == 0 || buf_y != NULL);
70828 return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
70829 }
70830
70831 /* Boolean/any -> coerce boolean to number and try again. If boolean is
70832 * compared to a pointer, the final comparison after coercion now always
70833 * yields false (as pointer vs. number compares to false), but this is
70834 * not special cased.
70835 */
70836 if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
70837 tv_tmp = tv_x;
70838 tv_x = tv_y;
70839 tv_y = tv_tmp;
70840 }
70841 if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
70842 /* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */
70843 duk_bool_t rc;
70844 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
70845 duk_push_tval(ctx, tv_x);
70846 duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
70847 rc = duk_js_equals_helper(thr,
70848 DUK_GET_TVAL_NEGIDX(ctx, -2),
70849 DUK_GET_TVAL_NEGIDX(ctx, -1),
70850 0 /*flags:nonstrict*/);
70851 duk_pop_2(ctx);
70852 return rc;
70853 }
70854
70855 /* String-number-buffer/object -> coerce object to primitive (apparently without hint), then try again. */
70856 if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
70857 DUK_TVAL_IS_OBJECT(tv_y)) {
70858 tv_tmp = tv_x;
70859 tv_x = tv_y;
70860 tv_y = tv_tmp;
70861 }
70862 if (DUK_TVAL_IS_OBJECT(tv_x) &&
70863 (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
70864 duk_bool_t rc;
70865 duk_push_tval(ctx, tv_x);
70866 duk_push_tval(ctx, tv_y);
70867 duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* apparently no hint? */
70868 rc = duk_js_equals_helper(thr,
70869 DUK_GET_TVAL_NEGIDX(ctx, -2),
70870 DUK_GET_TVAL_NEGIDX(ctx, -1),
70871 0 /*flags:nonstrict*/);
70872 duk_pop_2(ctx);
70873 return rc;
70874 }
70875
70876 /* Nothing worked -> not equal. */
70877 return 0;
70878}
70879
70880/*
70881 * Comparisons (x >= y, x > y, x <= y, x < y)
70882 *
70883 * E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
70884 * flags to get the rest.
70885 */
70886
70887/* XXX: this should probably just operate on the stack top, because it
70888 * needs to push stuff on the stack anyway...
70889 */
70890
70891DUK_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) {
70892 duk_size_t prefix_len;
70893 duk_small_int_t rc;
70894
70895 prefix_len = (len1 <= len2 ? len1 : len2);
70896
70897 /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length
70898 * inputs so no zero length check is needed.
70899 */
70900 rc = DUK_MEMCMP((const void *) buf1,
70901 (const void *) buf2,
70902 (size_t) prefix_len);
70903
70904 if (rc < 0) {
70905 return -1;
70906 } else if (rc > 0) {
70907 return 1;
70908 }
70909
70910 /* prefix matches, lengths matter now */
70911 if (len1 < len2) {
70912 /* e.g. "x" < "xx" */
70913 return -1;
70914 } else if (len1 > len2) {
70915 return 1;
70916 }
70917
70918 return 0;
70919}
70920
70921DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
70922 /*
70923 * String comparison (E5 Section 11.8.5, step 4), which
70924 * needs to compare codepoint by codepoint.
70925 *
70926 * However, UTF-8 allows us to use strcmp directly: the shared
70927 * prefix will be encoded identically (UTF-8 has unique encoding)
70928 * and the first differing character can be compared with a simple
70929 * unsigned byte comparison (which strcmp does).
70930 *
70931 * This will not work properly for non-xutf-8 strings, but this
70932 * is not an issue for compliance.
70933 */
70934
70935 DUK_ASSERT(h1 != NULL);
70936 DUK_ASSERT(h2 != NULL);
70937
70938 return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1),
70939 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2),
70940 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1),
70941 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2));
70942}
70943
70944#if 0 /* unused */
70945DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) {
70946 /* Similar to String comparison. */
70947
70948 DUK_ASSERT(h1 != NULL);
70949 DUK_ASSERT(h2 != NULL);
70950 DUK_UNREF(heap);
70951
70952 return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
70953 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
70954 (duk_size_t) DUK_HBUFFER_GET_SIZE(h1),
70955 (duk_size_t) DUK_HBUFFER_GET_SIZE(h2));
70956}
70957#endif
70958
70959DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
70960 duk_context *ctx = (duk_context *) thr;
70961 duk_double_t d1, d2;
70962 duk_small_int_t c1, c2;
70963 duk_small_int_t s1, s2;
70964 duk_small_int_t rc;
70965 duk_bool_t retval;
70966
70967 /* Fast path for fastints */
70968#if defined(DUK_USE_FASTINT)
70969 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
70970 duk_int64_t v1 = DUK_TVAL_GET_FASTINT(tv_x);
70971 duk_int64_t v2 = DUK_TVAL_GET_FASTINT(tv_y);
70972 if (v1 < v2) {
70973 /* 'lt is true' */
70974 retval = 1;
70975 } else {
70976 retval = 0;
70977 }
70978 if (flags & DUK_COMPARE_FLAG_NEGATE) {
70979 retval ^= 1;
70980 }
70981 return retval;
70982 }
70983#endif /* DUK_USE_FASTINT */
70984
70985 /* Fast path for numbers (one of which may be a fastint) */
70986#if 1 /* XXX: make fast paths optional for size minimization? */
70987 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
70988 d1 = DUK_TVAL_GET_NUMBER(tv_x);
70989 d2 = DUK_TVAL_GET_NUMBER(tv_y);
70990 c1 = DUK_FPCLASSIFY(d1);
70991 c2 = DUK_FPCLASSIFY(d2);
70992
70993 if (c1 == DUK_FP_NORMAL && c2 == DUK_FP_NORMAL) {
70994 /* XXX: this is a very narrow check, and doesn't cover
70995 * zeroes, subnormals, infinities, which compare normally.
70996 */
70997
70998 if (d1 < d2) {
70999 /* 'lt is true' */
71000 retval = 1;
71001 } else {
71002 retval = 0;
71003 }
71004 if (flags & DUK_COMPARE_FLAG_NEGATE) {
71005 retval ^= 1;
71006 }
71007 return retval;
71008 }
71009 }
71010#endif
71011
71012 /* Slow path */
71013
71014 duk_push_tval(ctx, tv_x);
71015 duk_push_tval(ctx, tv_y);
71016
71017 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
71018 duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
71019 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
71020 } else {
71021 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
71022 duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
71023 }
71024
71025 /* Note: reuse variables */
71026 tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
71027 tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
71028
71029 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
71030 duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
71031 duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
71032 DUK_ASSERT(h1 != NULL);
71033 DUK_ASSERT(h2 != NULL);
71034
71035 rc = duk_js_string_compare(h1, h2);
71036 if (rc < 0) {
71037 goto lt_true;
71038 } else {
71039 goto lt_false;
71040 }
71041 } else {
71042 /* Ordering should not matter (E5 Section 11.8.5, step 3.a) but
71043 * preserve it just in case.
71044 */
71045
71046 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
71047 d1 = duk_to_number(ctx, -2);
71048 d2 = duk_to_number(ctx, -1);
71049 } else {
71050 d2 = duk_to_number(ctx, -1);
71051 d1 = duk_to_number(ctx, -2);
71052 }
71053
71054 c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
71055 s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
71056 c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
71057 s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
71058
71059 if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
71060 goto lt_undefined;
71061 }
71062
71063 if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
71064 /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
71065 * steps e, f, and g.
71066 */
71067 goto lt_false;
71068 }
71069
71070 if (d1 == d2) {
71071 goto lt_false;
71072 }
71073
71074 if (c1 == DUK_FP_INFINITE && s1 == 0) {
71075 /* x == +Infinity */
71076 goto lt_false;
71077 }
71078
71079 if (c2 == DUK_FP_INFINITE && s2 == 0) {
71080 /* y == +Infinity */
71081 goto lt_true;
71082 }
71083
71084 if (c2 == DUK_FP_INFINITE && s2 != 0) {
71085 /* y == -Infinity */
71086 goto lt_false;
71087 }
71088
71089 if (c1 == DUK_FP_INFINITE && s1 != 0) {
71090 /* x == -Infinity */
71091 goto lt_true;
71092 }
71093
71094 if (d1 < d2) {
71095 goto lt_true;
71096 }
71097
71098 goto lt_false;
71099 }
71100
71101 lt_undefined:
71102 /* Note: undefined from Section 11.8.5 always results in false
71103 * return (see e.g. Section 11.8.3) - hence special treatment here.
71104 */
71105 retval = 0;
71106 goto cleanup;
71107
71108 lt_true:
71109 if (flags & DUK_COMPARE_FLAG_NEGATE) {
71110 retval = 0;
71111 goto cleanup;
71112 } else {
71113 retval = 1;
71114 goto cleanup;
71115 }
71116 /* never here */
71117
71118 lt_false:
71119 if (flags & DUK_COMPARE_FLAG_NEGATE) {
71120 retval = 1;
71121 goto cleanup;
71122 } else {
71123 retval = 0;
71124 goto cleanup;
71125 }
71126 /* never here */
71127
71128 cleanup:
71129 duk_pop_2(ctx);
71130 return retval;
71131}
71132
71133/*
71134 * instanceof
71135 */
71136
71137/*
71138 * E5 Section 11.8.6 describes the main algorithm, which uses
71139 * [[HasInstance]]. [[HasInstance]] is defined for only
71140 * function objects:
71141 *
71142 * - Normal functions:
71143 * E5 Section 15.3.5.3
71144 * - Functions established with Function.prototype.bind():
71145 * E5 Section 15.3.4.5.3
71146 *
71147 * For other objects, a TypeError is thrown.
71148 *
71149 * Limited Proxy support: don't support 'getPrototypeOf' trap but
71150 * continue lookup in Proxy target if the value is a Proxy.
71151 */
71152
71153DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
71154 duk_context *ctx = (duk_context *) thr;
71155 duk_hobject *func;
71156 duk_hobject *val;
71157 duk_hobject *proto;
71158 duk_uint_t sanity;
71159
71160 /*
71161 * Get the values onto the stack first. It would be possible to cover
71162 * some normal cases without resorting to the value stack.
71163 *
71164 * The right hand side could be a light function (as they generally
71165 * behave like objects). Light functions never have a 'prototype'
71166 * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
71167 * Using duk_require_hobject() is thus correct (except for error msg).
71168 */
71169
71170 duk_push_tval(ctx, tv_x);
71171 duk_push_tval(ctx, tv_y);
71172 func = duk_require_hobject(ctx, -1);
71173
71174 /*
71175 * For bound objects, [[HasInstance]] just calls the target function
71176 * [[HasInstance]]. If that is again a bound object, repeat until
71177 * we find a non-bound Function object.
71178 */
71179
71180 /* XXX: this bound function resolution also happens elsewhere,
71181 * move into a shared helper.
71182 */
71183
71184 sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
71185 do {
71186 /* check func supports [[HasInstance]] (this is checked for every function
71187 * in the bound chain, including the final one)
71188 */
71189
71190 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
71191 /*
71192 * Note: of native Ecmascript objects, only Function instances
71193 * have a [[HasInstance]] internal property. Custom objects might
71194 * also have it, but not in current implementation.
71195 *
71196 * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
71197 */
71198 DUK_ERROR_TYPE(thr, "invalid instanceof rval");
71199 }
71200
71201 if (!DUK_HOBJECT_HAS_BOUND(func)) {
71202 break;
71203 }
71204
71205 /* [ ... lval rval ] */
71206
71207 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */
71208 duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */
71209 func = duk_require_hobject(ctx, -1);
71210
71211 /* func support for [[HasInstance]] checked in the beginning of the loop */
71212 } while (--sanity > 0);
71213
71214 if (sanity == 0) {
71215 DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
71216 }
71217
71218 /*
71219 * 'func' is now a non-bound object which supports [[HasInstance]]
71220 * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on
71221 * to execute E5 Section 15.3.5.3.
71222 */
71223
71224 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
71225 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
71226
71227 /* [ ... lval rval(func) ] */
71228
71229 /* Handle lightfuncs through object coercion for now. */
71230 /* XXX: direct implementation */
71231 val = duk_get_hobject_or_lfunc_coerce(ctx, -2);
71232 if (!val) {
71233 goto pop_and_false;
71234 }
71235
71236 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
71237 proto = duk_require_hobject(ctx, -1);
71238 duk_pop(ctx); /* -> [ ... lval rval ] */
71239
71240 DUK_ASSERT(val != NULL);
71241
71242#if defined(DUK_USE_ES6_PROXY)
71243 val = duk_hobject_resolve_proxy_target(thr, val);
71244 DUK_ASSERT(val != NULL);
71245#endif
71246
71247 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
71248 do {
71249 /*
71250 * Note: prototype chain is followed BEFORE first comparison. This
71251 * means that the instanceof lval is never itself compared to the
71252 * rval.prototype property. This is apparently intentional, see E5
71253 * Section 15.3.5.3, step 4.a.
71254 *
71255 * Also note:
71256 *
71257 * js> (function() {}) instanceof Function
71258 * true
71259 * js> Function instanceof Function
71260 * true
71261 *
71262 * For the latter, h_proto will be Function.prototype, which is the
71263 * built-in Function prototype. Because Function.[[Prototype]] is
71264 * also the built-in Function prototype, the result is true.
71265 */
71266
71267 DUK_ASSERT(val != NULL);
71268 val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
71269
71270 if (!val) {
71271 goto pop_and_false;
71272 }
71273
71274 DUK_ASSERT(val != NULL);
71275#if defined(DUK_USE_ES6_PROXY)
71276 val = duk_hobject_resolve_proxy_target(thr, val);
71277#endif
71278
71279 if (val == proto) {
71280 goto pop_and_true;
71281 }
71282
71283 /* follow prototype chain */
71284 } while (--sanity > 0);
71285
71286 if (sanity == 0) {
71287 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
71288 }
71289 DUK_UNREACHABLE();
71290
71291 pop_and_false:
71292 duk_pop_2(ctx);
71293 return 0;
71294
71295 pop_and_true:
71296 duk_pop_2(ctx);
71297 return 1;
71298}
71299
71300/*
71301 * in
71302 */
71303
71304/*
71305 * E5 Sections 11.8.7, 8.12.6.
71306 *
71307 * Basically just a property existence check using [[HasProperty]].
71308 */
71309
71310DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
71311 duk_context *ctx = (duk_context *) thr;
71312 duk_bool_t retval;
71313
71314 /*
71315 * Get the values onto the stack first. It would be possible to cover
71316 * some normal cases without resorting to the value stack (e.g. if
71317 * lval is already a string).
71318 */
71319
71320 /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
71321 * must be string coerced before the internal HasProperty() algorithm is
71322 * invoked. A fast path skipping coercion could be safely implemented for
71323 * numbers (as number-to-string coercion has no side effects). For ES6
71324 * proxy behavior, the trap 'key' argument must be in a string coerced
71325 * form (which is a shame).
71326 */
71327
71328 /* TypeError if rval is not an object (or lightfunc which should behave
71329 * like a Function instance).
71330 */
71331 duk_push_tval(ctx, tv_x);
71332 duk_push_tval(ctx, tv_y);
71333 duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC);
71334 duk_to_string(ctx, -2); /* coerce lval with ToString() */
71335
71336 retval = duk_hobject_hasprop(thr,
71337 DUK_GET_TVAL_NEGIDX(ctx, -1),
71338 DUK_GET_TVAL_NEGIDX(ctx, -2));
71339
71340 duk_pop_2(ctx);
71341 return retval;
71342}
71343
71344/*
71345 * typeof
71346 *
71347 * E5 Section 11.4.3.
71348 *
71349 * Very straightforward. The only question is what to return for our
71350 * non-standard tag / object types.
71351 *
71352 * There is an unfortunate string constant define naming problem with
71353 * typeof return values for e.g. "Object" and "object"; careful with
71354 * the built-in string defines. The LC_XXX defines are used for the
71355 * lowercase variants now.
71356 */
71357
71358DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
71359 duk_small_int_t stridx = 0;
71360
71361 DUK_UNREF(thr);
71362
71363 switch (DUK_TVAL_GET_TAG(tv_x)) {
71364 case DUK_TAG_UNDEFINED: {
71365 stridx = DUK_STRIDX_LC_UNDEFINED;
71366 break;
71367 }
71368 case DUK_TAG_NULL: {
71369 /* Note: not a typo, "object" is returned for a null value */
71370 stridx = DUK_STRIDX_LC_OBJECT;
71371 break;
71372 }
71373 case DUK_TAG_BOOLEAN: {
71374 stridx = DUK_STRIDX_LC_BOOLEAN;
71375 break;
71376 }
71377 case DUK_TAG_POINTER: {
71378 /* implementation specific */
71379 stridx = DUK_STRIDX_LC_POINTER;
71380 break;
71381 }
71382 case DUK_TAG_STRING: {
71383 stridx = DUK_STRIDX_LC_STRING;
71384 break;
71385 }
71386 case DUK_TAG_OBJECT: {
71387 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
71388 DUK_ASSERT(obj != NULL);
71389 if (DUK_HOBJECT_IS_CALLABLE(obj)) {
71390 stridx = DUK_STRIDX_LC_FUNCTION;
71391 } else {
71392 stridx = DUK_STRIDX_LC_OBJECT;
71393 }
71394 break;
71395 }
71396 case DUK_TAG_BUFFER: {
71397 /* implementation specific */
71398 stridx = DUK_STRIDX_LC_BUFFER;
71399 break;
71400 }
71401 case DUK_TAG_LIGHTFUNC: {
71402 stridx = DUK_STRIDX_LC_FUNCTION;
71403 break;
71404 }
71405#if defined(DUK_USE_FASTINT)
71406 case DUK_TAG_FASTINT:
71407#endif
71408 default: {
71409 /* number */
71410 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
71411 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
71412 stridx = DUK_STRIDX_LC_NUMBER;
71413 break;
71414 }
71415 }
71416
71417 DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
71418 return DUK_HTHREAD_GET_STRING(thr, stridx);
71419}
71420
71421/*
71422 * Array index and length
71423 *
71424 * Array index: E5 Section 15.4
71425 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
71426 *
71427 * The DUK_HSTRING_GET_ARRIDX_SLOW() and DUK_HSTRING_GET_ARRIDX_FAST() macros
71428 * call duk_js_to_arrayindex_string_helper().
71429 */
71430
71431DUK_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) {
71432 duk_uarridx_t res;
71433
71434 if (blen == 0 || blen > 10) {
71435 goto parse_fail;
71436 }
71437 if (str[0] == DUK_ASC_0 && blen > 1) {
71438 goto parse_fail;
71439 }
71440
71441 /* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
71442 * Leading zeroes are not accepted (zero index "0" is an exception
71443 * handled above).
71444 */
71445
71446 res = 0;
71447 while (blen-- > 0) {
71448 duk_uint8_t c = *str++;
71449 if (c >= DUK_ASC_0 && c <= DUK_ASC_9) {
71450 /* Careful overflow handling. When multiplying by 10:
71451 * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding
71452 * 0...9 is safe.
71453 * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding
71454 * 0...5 is safe, 6...9 overflows.
71455 * - 0x1999999a x 10 = 0x100000004: always overflow.
71456 */
71457 if (DUK_UNLIKELY(res >= 0x19999999UL)) {
71458 if (res >= 0x1999999aUL) {
71459 /* Always overflow. */
71460 goto parse_fail;
71461 }
71462 DUK_ASSERT(res == 0x19999999UL);
71463 c -= DUK_ASC_0;
71464 if (c >= 6) {
71465 goto parse_fail;
71466 }
71467 res = 0xfffffffaUL + c;
71468 DUK_ASSERT(res >= 0xfffffffaUL);
71469 DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */
71470 } else {
71471 res = res * 10U + (duk_uint32_t) (c - DUK_ASC_0);
71472 }
71473 } else {
71474 goto parse_fail;
71475 }
71476 }
71477
71478 *out_idx = res;
71479 return 1;
71480
71481 parse_fail:
71482 *out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
71483 return 0;
71484}
71485
71486/* Called by duk_hstring.h macros */
71487DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
71488 duk_uarridx_t res;
71489 duk_small_int_t rc;
71490
71491 if (!DUK_HSTRING_HAS_ARRIDX(h)) {
71492 return DUK_HSTRING_NO_ARRAY_INDEX;
71493 }
71494
71495 rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h),
71496 DUK_HSTRING_GET_BYTELEN(h),
71497 &res);
71498 DUK_UNREF(rc);
71499 DUK_ASSERT(rc != 0);
71500 return res;
71501}
71502#line 1 "duk_js_var.c"
71503/*
71504 * Identifier access and function closure handling.
71505 *
71506 * Provides the primitives for slow path identifier accesses: GETVAR,
71507 * PUTVAR, DELVAR, etc. The fast path, direct register accesses, should
71508 * be used for most identifier accesses. Consequently, these slow path
71509 * primitives should be optimized for maximum compactness.
71510 *
71511 * Ecmascript environment records (declarative and object) are represented
71512 * as internal objects with control keys. Environment records have a
71513 * parent record ("outer environment reference") which is represented by
71514 * the implicit prototype for technical reasons (in other words, it is a
71515 * convenient field). The prototype chain is not followed in the ordinary
71516 * sense for variable lookups.
71517 *
71518 * See identifier-handling.rst for more details on the identifier algorithms
71519 * and the internal representation. See function-objects.rst for details on
71520 * what function templates and instances are expected to look like.
71521 *
71522 * Care must be taken to avoid duk_tval pointer invalidation caused by
71523 * e.g. value stack or object resizing.
71524 *
71525 * TODO: properties for function instances could be initialized much more
71526 * efficiently by creating a property allocation for a certain size and
71527 * filling in keys and values directly (and INCREFing both with "bulk incref"
71528 * primitives.
71529 *
71530 * XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit
71531 * awkward (especially because they follow the prototype chain); rework
71532 * if "raw" own property helpers are added.
71533 */
71534
71535/* include removed: duk_internal.h */
71536
71537/*
71538 * Local result type for duk__get_identifier_reference() lookup.
71539 */
71540
71541typedef struct {
71542 duk_hobject *holder; /* for object-bound identifiers */
71543 duk_tval *value; /* for register-bound and declarative env identifiers */
71544 duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */
71545 duk_tval *this_binding;
71546 duk_hobject *env;
71547} duk__id_lookup_result;
71548
71549/*
71550 * Create a new function object based on a "template function" which contains
71551 * compiled bytecode, constants, etc, but lacks a lexical environment.
71552 *
71553 * Ecmascript requires that each created closure is a separate object, with
71554 * its own set of editable properties. However, structured property values
71555 * (such as the formal arguments list and the variable map) are shared.
71556 * Also the bytecode, constants, and inner functions are shared.
71557 *
71558 * See E5 Section 13.2 for detailed requirements on the function objects;
71559 * there are no similar requirements for function "templates" which are an
71560 * implementation dependent internal feature. Also see function-objects.rst
71561 * for a discussion on the function instance properties provided by this
71562 * implementation.
71563 *
71564 * Notes:
71565 *
71566 * * Order of internal properties should match frequency of use, since the
71567 * properties will be linearly scanned on lookup (functions usually don't
71568 * have enough properties to warrant a hash part).
71569 *
71570 * * The created closure is independent of its template; they do share the
71571 * same 'data' buffer object, but the template object itself can be freed
71572 * even if the closure object remains reachable.
71573 */
71574
71575DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunction *f) {
71576 duk_tval *tv, *tv_end;
71577 duk_hobject **funcs, **funcs_end;
71578
71579 /* If function creation fails due to out-of-memory, the data buffer
71580 * pointer may be NULL in some cases. That's actually possible for
71581 * GC code, but shouldn't be possible here because the incomplete
71582 * function will be unwound from the value stack and never instantiated.
71583 */
71584 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL);
71585 DUK_UNREF(thr);
71586
71587 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
71588 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
71589 while (tv < tv_end) {
71590 DUK_TVAL_INCREF(thr, tv);
71591 tv++;
71592 }
71593
71594 funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
71595 funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
71596 while (funcs < funcs_end) {
71597 DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
71598 funcs++;
71599 }
71600}
71601
71602/* Push a new closure on the stack.
71603 *
71604 * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration
71605 * is created when the function is called, only outer_lex_env matters
71606 * (outer_var_env is ignored and may or may not be same as outer_lex_env).
71607 */
71608
71609DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
71610 /* order: most frequent to least frequent */
71611 DUK_STRIDX_INT_VARMAP,
71612 DUK_STRIDX_INT_FORMALS,
71613 DUK_STRIDX_NAME,
71614 DUK_STRIDX_INT_PC2LINE,
71615 DUK_STRIDX_FILE_NAME,
71616 DUK_STRIDX_INT_SOURCE
71617};
71618
71619DUK_INTERNAL
71620void duk_js_push_closure(duk_hthread *thr,
71621 duk_hcompiledfunction *fun_temp,
71622 duk_hobject *outer_var_env,
71623 duk_hobject *outer_lex_env,
71624 duk_bool_t add_auto_proto) {
71625 duk_context *ctx = (duk_context *) thr;
71626 duk_hcompiledfunction *fun_clos;
71627 duk_small_uint_t i;
71628 duk_uint_t len_value;
71629
71630 DUK_ASSERT(fun_temp != NULL);
71631 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp) != NULL);
71632 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp) != NULL);
71633 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp) != NULL);
71634 DUK_ASSERT(outer_var_env != NULL);
71635 DUK_ASSERT(outer_lex_env != NULL);
71636 DUK_UNREF(len_value);
71637
71638 duk_push_compiledfunction(ctx);
71639 duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
71640
71641 fun_clos = (duk_hcompiledfunction *) duk_get_hcompiledfunction(ctx, -2);
71642 DUK_ASSERT(fun_clos != NULL);
71643 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun_clos));
71644 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) == NULL);
71645 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) == NULL);
71646 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) == NULL);
71647
71648 DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp));
71649 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp));
71650 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp));
71651
71652 /* Note: all references inside 'data' need to get their refcounts
71653 * upped too. This is the case because refcounts are decreased
71654 * through every function referencing 'data' independently.
71655 */
71656
71657 DUK_HBUFFER_INCREF(thr, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos));
71658 duk__inc_data_inner_refcounts(thr, fun_temp);
71659
71660 fun_clos->nregs = fun_temp->nregs;
71661 fun_clos->nargs = fun_temp->nargs;
71662#if defined(DUK_USE_DEBUGGER_SUPPORT)
71663 fun_clos->start_line = fun_temp->start_line;
71664 fun_clos->end_line = fun_temp->end_line;
71665#endif
71666
71667 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) != NULL);
71668 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) != NULL);
71669 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) != NULL);
71670
71671 /* XXX: could also copy from template, but there's no way to have any
71672 * other value here now (used code has no access to the template).
71673 */
71674 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
71675
71676 /*
71677 * Init/assert flags, copying them where appropriate. Some flags
71678 * (like NEWENV) are processed separately below.
71679 */
71680
71681 /* XXX: copy flags using a mask */
71682
71683 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
71684 DUK_HOBJECT_SET_CONSTRUCTABLE(&fun_clos->obj); /* Note: not set in template (has no "prototype") */
71685 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj));
71686 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&fun_clos->obj));
71687 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&fun_clos->obj));
71688 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&fun_clos->obj));
71689 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj));
71690 /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
71691 if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
71692 DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
71693 }
71694 if (DUK_HOBJECT_HAS_NOTAIL(&fun_temp->obj)) {
71695 DUK_HOBJECT_SET_NOTAIL(&fun_clos->obj);
71696 }
71697 /* DUK_HOBJECT_FLAG_NEWENV: handled below */
71698 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
71699 /* Although NAMEBINDING is not directly needed for using
71700 * function instances, it's needed by bytecode dump/load
71701 * so copy it too.
71702 */
71703 DUK_HOBJECT_SET_NAMEBINDING(&fun_clos->obj);
71704 }
71705 if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {
71706 DUK_HOBJECT_SET_CREATEARGS(&fun_clos->obj);
71707 }
71708 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj));
71709 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj));
71710 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj));
71711
71712 /*
71713 * Setup environment record properties based on the template and
71714 * its flags.
71715 *
71716 * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
71717 * records represent identifiers "outside" the function; the
71718 * "inner" environment records are created on demand. Otherwise,
71719 * the environment records are those that will be directly used
71720 * (e.g. for declarations).
71721 *
71722 * _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
71723 * so _Varenv is only set if _Lexenv != _Varenv.
71724 *
71725 * This is relatively complex, see doc/identifier-handling.rst.
71726 */
71727
71728 if (DUK_HOBJECT_HAS_NEWENV(&fun_temp->obj)) {
71729 DUK_HOBJECT_SET_NEWENV(&fun_clos->obj);
71730
71731 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
71732 duk_hobject *proto;
71733
71734 /*
71735 * Named function expression, name needs to be bound
71736 * in an intermediate environment record. The "outer"
71737 * lexical/variable environment will thus be:
71738 *
71739 * a) { funcname: <func>, __prototype: outer_lex_env }
71740 * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
71741 */
71742
71743 DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_NAME)); /* required if NAMEBINDING set */
71744
71745 if (outer_lex_env) {
71746 proto = outer_lex_env;
71747 } else {
71748 proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
71749 }
71750
71751 /* -> [ ... closure template env ] */
71752 (void) duk_push_object_helper_proto(ctx,
71753 DUK_HOBJECT_FLAG_EXTENSIBLE |
71754 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
71755 proto);
71756
71757 /* It's important that duk_xdef_prop() is a 'raw define' so that any
71758 * properties in an ancestor are never an issue (they should never be
71759 * e.g. non-writable, but just in case).
71760 */
71761 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); /* -> [ ... closure template env funcname ] */
71762 duk_dup(ctx, -4); /* -> [ ... closure template env funcname closure ] */
71763 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
71764 /* env[funcname] = closure */
71765
71766 /* [ ... closure template env ] */
71767
71768 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
71769 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
71770 * will be ignored anyway
71771 */
71772
71773 /* [ ... closure template ] */
71774 } else {
71775 /*
71776 * Other cases (function declaration, anonymous function expression,
71777 * strict direct eval code). The "outer" environment will be whatever
71778 * the caller gave us.
71779 */
71780
71781 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
71782 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
71783 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
71784 * will be ignored anyway
71785 */
71786
71787 /* [ ... closure template ] */
71788 }
71789 } else {
71790 /*
71791 * Function gets no new environment when called. This is the
71792 * case for global code, indirect eval code, and non-strict
71793 * direct eval code. There is no direct correspondence to the
71794 * E5 specification, as global/eval code is not exposed as a
71795 * function.
71796 */
71797
71798 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
71799
71800 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
71801 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
71802
71803 if (outer_var_env != outer_lex_env) {
71804 duk_push_hobject(ctx, outer_var_env); /* -> [ ... closure template env ] */
71805 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_WC);
71806 }
71807 }
71808#ifdef DUK_USE_DDDPRINT
71809 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARENV);
71810 duk_get_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV);
71811 DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipT, lexenv -> %!ipT",
71812 (duk_tval *) duk_get_tval(ctx, -2),
71813 (duk_tval *) duk_get_tval(ctx, -1)));
71814 duk_pop_2(ctx);
71815#endif
71816
71817 /*
71818 * Copy some internal properties directly
71819 *
71820 * The properties will be writable and configurable, but not enumerable.
71821 */
71822
71823 /* [ ... closure template ] */
71824
71825 DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
71826 (duk_tval *) duk_get_tval(ctx, -2),
71827 (duk_tval *) duk_get_tval(ctx, -1)));
71828
71829 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
71830 duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
71831 if (duk_get_prop_stridx(ctx, -1, stridx)) {
71832 /* [ ... closure template val ] */
71833 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
71834 duk_xdef_prop_stridx(ctx, -3, stridx, DUK_PROPDESC_FLAGS_WC);
71835 } else {
71836 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
71837 duk_pop(ctx);
71838 }
71839 }
71840
71841 /*
71842 * "length" maps to number of formals (E5 Section 13.2) for function
71843 * declarations/expressions (non-bound functions). Note that 'nargs'
71844 * is NOT necessarily equal to the number of arguments.
71845 */
71846
71847 /* [ ... closure template ] */
71848
71849 len_value = 0;
71850
71851 /* XXX: use helper for size optimization */
71852 if (duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS)) {
71853 /* [ ... closure template formals ] */
71854 DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH));
71855 DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_UINT_MAX); /* formal arg limits */
71856 len_value = (duk_uint_t) duk_get_length(ctx, -1);
71857 } else {
71858 /* XXX: what to do if _Formals is not empty but compiler has
71859 * optimized it away -- read length from an explicit property
71860 * then?
71861 */
71862 }
71863 duk_pop(ctx);
71864
71865 duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
71866 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
71867
71868 /*
71869 * "prototype" is, by default, a fresh object with the "constructor"
71870 * property.
71871 *
71872 * Note that this creates a circular reference for every function
71873 * instance (closure) which prevents refcount-based collection of
71874 * function instances.
71875 *
71876 * XXX: Try to avoid creating the default prototype object, because
71877 * many functions are not used as constructors and the default
71878 * prototype is unnecessary. Perhaps it could be created on-demand
71879 * when it is first accessed?
71880 */
71881
71882 /* [ ... closure template ] */
71883
71884 if (add_auto_proto) {
71885 duk_push_object(ctx); /* -> [ ... closure template newobj ] */
71886 duk_dup(ctx, -3); /* -> [ ... closure template newobj closure ] */
71887 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
71888 duk_compact(ctx, -1); /* compact the prototype */
71889 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
71890 }
71891
71892 /*
71893 * "arguments" and "caller" must be mapped to throwers for strict
71894 * mode and bound functions (E5 Section 15.3.5).
71895 *
71896 * XXX: This is expensive to have for every strict function instance.
71897 * Try to implement as virtual properties or on-demand created properties.
71898 */
71899
71900 /* [ ... closure template ] */
71901
71902 if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
71903 duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
71904 duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
71905 } else {
71906#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
71907 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
71908 duk_push_null(ctx);
71909 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
71910#else
71911 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
71912#endif
71913 }
71914
71915 /*
71916 * "name" is a non-standard property found in at least V8, Rhino, smjs.
71917 * For Rhino and smjs it is non-writable, non-enumerable, and non-configurable;
71918 * for V8 it is writable, non-enumerable, non-configurable. It is also defined
71919 * for an anonymous function expression in which case the value is an empty string.
71920 * We could also leave name 'undefined' for anonymous functions but that would
71921 * differ from behavior of other engines, so use an empty string.
71922 *
71923 * XXX: make optional? costs something per function.
71924 */
71925
71926 /* [ ... closure template ] */
71927
71928 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME)) {
71929 /* [ ... closure template name ] */
71930 DUK_ASSERT(duk_is_string(ctx, -1));
71931 } else {
71932 /* [ ... closure template undefined ] */
71933 duk_pop(ctx);
71934 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
71935 }
71936 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template ] */
71937
71938 /*
71939 * Compact the closure, in most cases no properties will be added later.
71940 * Also, without this the closures end up having unused property slots
71941 * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
71942 * A better future solution would be to allocate the closure directly
71943 * to correct size (and setup the properties directly without going
71944 * through the API).
71945 */
71946
71947 duk_compact(ctx, -2);
71948
71949 /*
71950 * Some assertions (E5 Section 13.2).
71951 */
71952
71953 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
71954 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
71955 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
71956 DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH) != 0);
71957 DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
71958 DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_NAME) != 0); /* non-standard */
71959 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
71960 duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
71961 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
71962 duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
71963
71964 /*
71965 * Finish
71966 */
71967
71968 /* [ ... closure template ] */
71969
71970 DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
71971 (duk_tval *) duk_get_tval(ctx, -1),
71972 (duk_tval *) duk_get_tval(ctx, -2)));
71973
71974 duk_pop(ctx);
71975
71976 /* [ ... closure ] */
71977}
71978
71979/*
71980 * Delayed activation environment record initialization (for functions
71981 * with NEWENV).
71982 *
71983 * The non-delayed initialization is handled by duk_handle_call().
71984 */
71985
71986/* shared helper */
71987DUK_INTERNAL
71988duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
71989 duk_hobject *func,
71990 duk_size_t idx_bottom) {
71991 duk_context *ctx = (duk_context *) thr;
71992 duk_hobject *env;
71993 duk_hobject *parent;
71994 duk_tval *tv;
71995
71996 DUK_ASSERT(thr != NULL);
71997 DUK_ASSERT(func != NULL);
71998
71999 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
72000 if (tv) {
72001 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72002 DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
72003 parent = DUK_TVAL_GET_OBJECT(tv);
72004 } else {
72005 parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
72006 }
72007
72008 (void) duk_push_object_helper(ctx,
72009 DUK_HOBJECT_FLAG_EXTENSIBLE |
72010 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
72011 -1); /* no prototype, updated below */
72012 env = duk_require_hobject(ctx, -1);
72013 DUK_ASSERT(env != NULL);
72014 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */
72015
72016 /* open scope information, for compiled functions only */
72017
72018 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
72019 duk_push_hthread(ctx, thr);
72020 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_THREAD);
72021 duk_push_hobject(ctx, func);
72022 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_CALLEE);
72023 duk_push_size_t(ctx, idx_bottom);
72024 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_REGBASE);
72025 }
72026
72027 return env;
72028}
72029
72030DUK_INTERNAL
72031void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
72032 duk_activation *act) {
72033 duk_context *ctx = (duk_context *) thr;
72034 duk_hobject *func;
72035 duk_hobject *env;
72036 duk_size_t act_off;
72037
72038 DUK_ASSERT(act != NULL);
72039 act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
72040 func = DUK_ACT_GET_FUNC(act);
72041 DUK_ASSERT(func != NULL);
72042 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound functions are never in act 'func' */
72043
72044 /*
72045 * Delayed initialization only occurs for 'NEWENV' functions.
72046 */
72047
72048 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
72049 DUK_ASSERT(act->lex_env == NULL);
72050 DUK_ASSERT(act->var_env == NULL);
72051
72052 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
72053 DUK_ASSERT(env != NULL);
72054 act = (duk_activation *) ((duk_uint8_t *) thr->callstack + act_off);
72055
72056 DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
72057#ifdef DUK_USE_DDDPRINT
72058 {
72059 duk_hobject *p = env;
72060 while (p) {
72061 DUK_DDD(DUK_DDDPRINT(" -> %!ipO", (duk_heaphdr *) p));
72062 p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p);
72063 }
72064 }
72065#endif
72066
72067 act->lex_env = env;
72068 act->var_env = env;
72069 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
72070 DUK_HOBJECT_INCREF(thr, env);
72071
72072 duk_pop(ctx);
72073}
72074
72075/*
72076 * Closing environment records.
72077 *
72078 * The environment record MUST be closed with the thread where its activation
72079 * is. In other words (if 'env' is open):
72080 *
72081 * - 'thr' must match _env.thread
72082 * - 'func' must match _env.callee
72083 * - 'regbase' must match _env.regbase
72084 *
72085 * These are not looked up from the env to minimize code size.
72086 *
72087 * XXX: should access the own properties directly instead of using the API
72088 */
72089
72090DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) {
72091 duk_context *ctx = (duk_context *) thr;
72092 duk_uint_fast32_t i;
72093
72094 DUK_ASSERT(thr != NULL);
72095 DUK_ASSERT(env != NULL);
72096 /* func is NULL for lightfuncs */
72097
72098 if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
72099 DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, "
72100 "or already closed: %!iO",
72101 (duk_heaphdr *) env));
72102 return;
72103 }
72104
72105 DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld",
72106 (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase));
72107
72108 duk_push_hobject(ctx, env);
72109
72110 /* assertions: env must be closed in the same thread as where it runs */
72111#ifdef DUK_USE_ASSERTIONS
72112 {
72113 /* [... env] */
72114
72115 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
72116 DUK_ASSERT(duk_is_object(ctx, -1));
72117 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
72118 }
72119 duk_pop(ctx);
72120
72121 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD)) {
72122 DUK_ASSERT(duk_is_object(ctx, -1));
72123 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
72124 }
72125 duk_pop(ctx);
72126
72127 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE)) {
72128 DUK_ASSERT(duk_is_number(ctx, -1));
72129 DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
72130 }
72131 duk_pop(ctx);
72132
72133 /* [... env] */
72134 }
72135#endif
72136
72137 if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
72138 duk_hobject *varmap;
72139 duk_hstring *key;
72140 duk_tval *tv;
72141 duk_uint_t regnum;
72142
72143 /* XXX: additional conditions when to close variables? we don't want to do it
72144 * unless the environment may have "escaped" (referenced in a function closure).
72145 * With delayed environments, the existence is probably good enough of a check.
72146 */
72147
72148 /* XXX: any way to detect faster whether something needs to be closed?
72149 * We now look up _Callee and then skip the rest.
72150 */
72151
72152 /* Note: we rely on the _Varmap having a bunch of nice properties, like:
72153 * - being compacted and unmodified during this process
72154 * - not containing an array part
72155 * - having correct value types
72156 */
72157
72158 /* [... env] */
72159
72160 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
72161 DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case"));
72162 duk_pop(ctx);
72163 goto skip_varmap;
72164 }
72165
72166 /* [... env callee] */
72167
72168 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP)) {
72169 DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties"));
72170 duk_pop_2(ctx);
72171 goto skip_varmap;
72172 }
72173 varmap = duk_require_hobject(ctx, -1);
72174 DUK_ASSERT(varmap != NULL);
72175
72176 DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
72177
72178 /* [... env callee varmap] */
72179
72180 DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
72181
72182 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
72183 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
72184 DUK_ASSERT(key != NULL); /* assume keys are compacted */
72185
72186 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
72187
72188 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
72189 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */
72190 regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
72191 DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */
72192 DUK_ASSERT(regnum < ((duk_hcompiledfunction *) func)->nregs); /* regnum is sane */
72193 DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
72194 DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
72195
72196 /* XXX: slightly awkward */
72197 duk_push_hstring(ctx, key);
72198 duk_push_tval(ctx, thr->valstack + regbase + regnum);
72199 DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T",
72200 (const char *) duk_require_string(ctx, -2),
72201 (long) regnum,
72202 (duk_tval *) duk_get_tval(ctx, -1)));
72203
72204 /* [... env callee varmap key val] */
72205
72206 /* if property already exists, overwrites silently */
72207 duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */
72208 }
72209
72210 duk_pop_2(ctx);
72211
72212 /* [... env] */
72213 }
72214
72215 skip_varmap:
72216
72217 /* [... env] */
72218
72219 duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE);
72220 duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD);
72221 duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE);
72222
72223 duk_pop(ctx);
72224
72225 DUK_HOBJECT_SET_ENVRECCLOSED(env);
72226
72227 DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O",
72228 (duk_heaphdr *) env));
72229}
72230
72231/*
72232 * GETIDREF: a GetIdentifierReference-like helper.
72233 *
72234 * Provides a parent traversing lookup and a single level lookup
72235 * (for HasBinding).
72236 *
72237 * Instead of returning the value, returns a bunch of values allowing
72238 * the caller to read, write, or delete the binding. Value pointers
72239 * are duk_tval pointers which can be mutated directly as long as
72240 * refcounts are properly updated. Note that any operation which may
72241 * reallocate valstacks or compact objects may invalidate the returned
72242 * duk_tval (but not object) pointers, so caller must be very careful.
72243 *
72244 * If starting environment record 'env' is given, 'act' is ignored.
72245 * However, if 'env' is NULL, the caller may identify, in 'act', an
72246 * activation which hasn't had its declarative environment initialized
72247 * yet. The activation registers are then looked up, and its parent
72248 * traversed normally.
72249 *
72250 * The 'out' structure values are only valid if the function returns
72251 * success (non-zero).
72252 */
72253
72254/* lookup name from an open declarative record's registers */
72255DUK_LOCAL
72256duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
72257 duk_hstring *name,
72258 duk_hobject *env,
72259 duk__id_lookup_result *out) {
72260 duk_hthread *env_thr;
72261 duk_hobject *env_func;
72262 duk_size_t env_regbase;
72263 duk_hobject *varmap;
72264 duk_tval *tv;
72265 duk_size_t reg_rel;
72266 duk_size_t idx;
72267
72268 DUK_ASSERT(thr != NULL);
72269 DUK_ASSERT(name != NULL);
72270 DUK_ASSERT(env != NULL);
72271 DUK_ASSERT(out != NULL);
72272
72273 DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env));
72274
72275 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr));
72276 if (!tv) {
72277 /* env is closed, should be missing _Callee, _Thread, _Regbase */
72278 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL);
72279 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL);
72280 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL);
72281 return 0;
72282 }
72283
72284 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72285 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
72286 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(tv)));
72287 env_func = DUK_TVAL_GET_OBJECT(tv);
72288 DUK_ASSERT(env_func != NULL);
72289
72290 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
72291 if (!tv) {
72292 return 0;
72293 }
72294 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72295 varmap = DUK_TVAL_GET_OBJECT(tv);
72296 DUK_ASSERT(varmap != NULL);
72297
72298 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
72299 if (!tv) {
72300 return 0;
72301 }
72302 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
72303 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
72304 DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
72305 DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) env_func)->nregs);
72306
72307 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr));
72308 DUK_ASSERT(tv != NULL);
72309 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72310 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
72311 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
72312 env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
72313 DUK_ASSERT(env_thr != NULL);
72314
72315 /* Note: env_thr != thr is quite possible and normal, so careful
72316 * with what thread is used for valstack lookup.
72317 */
72318
72319 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr));
72320 DUK_ASSERT(tv != NULL);
72321 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
72322 env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
72323
72324 idx = env_regbase + reg_rel;
72325 tv = env_thr->valstack + idx;
72326 DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */
72327
72328 out->value = tv;
72329 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
72330 out->this_binding = NULL; /* implicit this value always undefined for
72331 * declarative environment records.
72332 */
72333 out->env = env;
72334 out->holder = NULL;
72335
72336 return 1;
72337}
72338
72339/* lookup name from current activation record's functions' registers */
72340DUK_LOCAL
72341duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
72342 duk_hstring *name,
72343 duk_activation *act,
72344 duk__id_lookup_result *out) {
72345 duk_tval *tv;
72346 duk_hobject *func;
72347 duk_hobject *varmap;
72348 duk_size_t reg_rel;
72349 duk_size_t idx;
72350
72351 DUK_ASSERT(thr != NULL);
72352 DUK_ASSERT(name != NULL);
72353 DUK_ASSERT(act != NULL);
72354 DUK_ASSERT(out != NULL);
72355
72356 func = DUK_ACT_GET_FUNC(act);
72357 DUK_ASSERT(func != NULL);
72358 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
72359
72360 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
72361 return 0;
72362 }
72363
72364 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
72365 if (!tv) {
72366 return 0;
72367 }
72368 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72369 varmap = DUK_TVAL_GET_OBJECT(tv);
72370 DUK_ASSERT(varmap != NULL);
72371
72372 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
72373 if (!tv) {
72374 return 0;
72375 }
72376 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
72377 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
72378 DUK_ASSERT_DISABLE(reg_rel >= 0);
72379 DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) func)->nregs);
72380
72381 idx = act->idx_bottom + reg_rel;
72382 DUK_ASSERT(idx >= act->idx_bottom);
72383 tv = thr->valstack + idx;
72384
72385 out->value = tv;
72386 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
72387 out->this_binding = NULL; /* implicit this value always undefined for
72388 * declarative environment records.
72389 */
72390 out->env = NULL;
72391 out->holder = NULL;
72392
72393 return 1;
72394}
72395
72396DUK_LOCAL
72397duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
72398 duk_hobject *env,
72399 duk_hstring *name,
72400 duk_activation *act,
72401 duk_bool_t parents,
72402 duk__id_lookup_result *out) {
72403 duk_tval *tv;
72404 duk_tval *tv_target;
72405 duk_tval tv_name;
72406 duk_uint_t sanity;
72407
72408 DUK_ASSERT(thr != NULL);
72409 DUK_ASSERT(env != NULL || act != NULL);
72410 DUK_ASSERT(name != NULL);
72411 DUK_ASSERT(out != NULL);
72412
72413 DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
72414 DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env));
72415
72416 /*
72417 * Conceptually, we look for the identifier binding by starting from
72418 * 'env' and following to chain of environment records (represented
72419 * by the prototype chain).
72420 *
72421 * If 'env' is NULL, the current activation does not yet have an
72422 * allocated declarative environment record; this should be treated
72423 * exactly as if the environment record existed but had no bindings
72424 * other than register bindings.
72425 *
72426 * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
72427 * the environment will always be initialized immediately; hence
72428 * a NULL 'env' should only happen with the flag set. This is the
72429 * case for: (1) function calls, and (2) strict, direct eval calls.
72430 */
72431
72432 if (env == NULL && act != NULL) {
72433 duk_hobject *func;
72434
72435 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
72436 "delayed env case, look up activation regs first"));
72437
72438 /*
72439 * Try registers
72440 */
72441
72442 if (duk__getid_activation_regs(thr, name, act, out)) {
72443 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72444 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72445 "(found from register bindings when env=NULL)",
72446 (duk_heaphdr *) name, (duk_tval *) out->value,
72447 (long) out->attrs, (duk_tval *) out->this_binding,
72448 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72449 return 1;
72450 }
72451
72452 DUK_DDD(DUK_DDDPRINT("not found in current activation regs"));
72453
72454 /*
72455 * Not found in registers, proceed to the parent record.
72456 * Here we need to determine what the parent would be,
72457 * if 'env' was not NULL (i.e. same logic as when initializing
72458 * the record).
72459 *
72460 * Note that environment initialization is only deferred when
72461 * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
72462 * - Function code
72463 * - Strict eval code
72464 *
72465 * We only need to check _Lexenv here; _Varenv exists only if it
72466 * differs from _Lexenv (and thus _Lexenv will also be present).
72467 */
72468
72469 if (!parents) {
72470 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
72471 "(not found from register bindings when env=NULL)"));
72472 goto fail_not_found;
72473 }
72474
72475 func = DUK_ACT_GET_FUNC(act);
72476 DUK_ASSERT(func != NULL);
72477 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
72478
72479 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
72480 if (tv) {
72481 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72482 env = DUK_TVAL_GET_OBJECT(tv);
72483 } else {
72484 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr)) == NULL);
72485 env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
72486 }
72487
72488 DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO",
72489 (duk_heaphdr *) env));
72490 }
72491
72492 /*
72493 * Prototype walking starting from 'env'.
72494 *
72495 * ('act' is not needed anywhere here.)
72496 */
72497
72498 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
72499 while (env != NULL) {
72500 duk_small_int_t cl;
72501 duk_int_t attrs;
72502
72503 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
72504 (duk_heaphdr *) name,
72505 (void *) env,
72506 (duk_heaphdr *) env));
72507
72508 DUK_ASSERT(env != NULL);
72509 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
72510 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
72511
72512 cl = DUK_HOBJECT_GET_CLASS_NUMBER(env);
72513 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV);
72514 if (cl == DUK_HOBJECT_CLASS_DECENV) {
72515 /*
72516 * Declarative environment record.
72517 *
72518 * Identifiers can never be stored in ancestors and are
72519 * always plain values, so we can use an internal helper
72520 * and access the value directly with an duk_tval ptr.
72521 *
72522 * A closed environment is only indicated by it missing
72523 * the "book-keeping" properties required for accessing
72524 * register-bound variables.
72525 */
72526
72527 if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
72528 /* already closed */
72529 goto skip_regs;
72530 }
72531
72532 if (duk__getid_open_decl_env_regs(thr, name, env, out)) {
72533 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72534 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72535 "(declarative environment record, scope open, found in regs)",
72536 (duk_heaphdr *) name, (duk_tval *) out->value,
72537 (long) out->attrs, (duk_tval *) out->this_binding,
72538 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72539 return 1;
72540 }
72541 skip_regs:
72542
72543 tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs);
72544 if (tv) {
72545 out->value = tv;
72546 out->attrs = attrs;
72547 out->this_binding = NULL; /* implicit this value always undefined for
72548 * declarative environment records.
72549 */
72550 out->env = env;
72551 out->holder = env;
72552
72553 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72554 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72555 "(declarative environment record, found in properties)",
72556 (duk_heaphdr *) name, (duk_tval *) out->value,
72557 (long) out->attrs, (duk_tval *) out->this_binding,
72558 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72559 return 1;
72560 }
72561 } else {
72562 /*
72563 * Object environment record.
72564 *
72565 * Binding (target) object is an external, uncontrolled object.
72566 * Identifier may be bound in an ancestor property, and may be
72567 * an accessor. Target can also be a Proxy which we must support
72568 * here.
72569 */
72570
72571 /* XXX: we could save space by using _Target OR _This. If _Target, assume
72572 * this binding is undefined. If _This, assumes this binding is _This, and
72573 * target is also _This. One property would then be enough.
72574 */
72575
72576 duk_hobject *target;
72577 duk_bool_t found;
72578
72579 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
72580
72581 tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
72582 DUK_ASSERT(tv_target != NULL);
72583 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
72584 target = DUK_TVAL_GET_OBJECT(tv_target);
72585 DUK_ASSERT(target != NULL);
72586
72587 /* Target may be a Proxy or property may be an accessor, so we must
72588 * use an actual, Proxy-aware hasprop check here.
72589 *
72590 * out->holder is NOT set to the actual duk_hobject where the
72591 * property is found, but rather the object binding target object.
72592 */
72593
72594 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) {
72595 DUK_ASSERT(name != NULL);
72596 DUK_TVAL_SET_STRING(&tv_name, name);
72597
72598 found = duk_hobject_hasprop(thr, tv_target, &tv_name);
72599 } else {
72600 /* XXX: duk_hobject_hasprop() would be correct for
72601 * non-Proxy objects too, but it is about ~20-25%
72602 * slower at present so separate code paths for
72603 * Proxy and non-Proxy now.
72604 */
72605 found = duk_hobject_hasprop_raw(thr, target, name);
72606 }
72607
72608 if (found) {
72609 out->value = NULL; /* can't get value, may be accessor */
72610 out->attrs = 0; /* irrelevant when out->value == NULL */
72611 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr));
72612 out->this_binding = tv; /* may be NULL */
72613 out->env = env;
72614 out->holder = target;
72615
72616 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72617 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72618 "(object environment record)",
72619 (duk_heaphdr *) name, (duk_tval *) out->value,
72620 (long) out->attrs, (duk_tval *) out->this_binding,
72621 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72622 return 1;
72623 }
72624 }
72625
72626 if (!parents) {
72627 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
72628 "(not found from first traversed env)"));
72629 goto fail_not_found;
72630 }
72631
72632 if (sanity-- == 0) {
72633 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
72634 }
72635 env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
72636 };
72637
72638 /*
72639 * Not found (even in global object)
72640 */
72641
72642 fail_not_found:
72643 return 0;
72644}
72645
72646/*
72647 * HASVAR: check identifier binding from a given environment record
72648 * without traversing its parents.
72649 *
72650 * This primitive is not exposed to user code as such, but is used
72651 * internally for e.g. declaration binding instantiation.
72652 *
72653 * See E5 Sections:
72654 * 10.2.1.1.1 HasBinding(N)
72655 * 10.2.1.2.1 HasBinding(N)
72656 *
72657 * Note: strictness has no bearing on this check. Hence we don't take
72658 * a 'strict' parameter.
72659 */
72660
72661#if 0 /*unused*/
72662DUK_INTERNAL
72663duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr,
72664 duk_hobject *env,
72665 duk_hstring *name) {
72666 duk__id_lookup_result ref;
72667 duk_bool_t parents;
72668
72669 DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O "
72670 "(env -> %!dO)",
72671 (void *) thr, (void *) env, (duk_heaphdr *) name,
72672 (duk_heaphdr *) env));
72673
72674 DUK_ASSERT(thr != NULL);
72675 DUK_ASSERT(env != NULL);
72676 DUK_ASSERT(name != NULL);
72677
72678 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
72679 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72680
72681 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
72682 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
72683
72684 /* lookup results is ignored */
72685 parents = 0;
72686 return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref);
72687}
72688#endif
72689
72690/*
72691 * GETVAR
72692 *
72693 * See E5 Sections:
72694 * 11.1.2 Identifier Reference
72695 * 10.3.1 Identifier Resolution
72696 * 11.13.1 Simple Assignment [example of where the Reference is GetValue'd]
72697 * 8.7.1 GetValue (V)
72698 * 8.12.1 [[GetOwnProperty]] (P)
72699 * 8.12.2 [[GetProperty]] (P)
72700 * 8.12.3 [[Get]] (P)
72701 *
72702 * If 'throw' is true, always leaves two values on top of stack: [val this].
72703 *
72704 * If 'throw' is false, returns 0 if identifier cannot be resolved, and the
72705 * stack will be unaffected in this case. If identifier is resolved, returns
72706 * 1 and leaves [val this] on top of stack.
72707 *
72708 * Note: the 'strict' flag of a reference returned by GetIdentifierReference
72709 * is ignored by GetValue. Hence we don't take a 'strict' parameter.
72710 *
72711 * The 'throw' flag is needed for implementing 'typeof' for an unreferenced
72712 * identifier. An unreference identifier in other contexts generates a
72713 * ReferenceError.
72714 */
72715
72716DUK_LOCAL
72717duk_bool_t duk__getvar_helper(duk_hthread *thr,
72718 duk_hobject *env,
72719 duk_activation *act,
72720 duk_hstring *name,
72721 duk_bool_t throw_flag) {
72722 duk_context *ctx = (duk_context *) thr;
72723 duk__id_lookup_result ref;
72724 duk_tval tv_tmp_obj;
72725 duk_tval tv_tmp_key;
72726 duk_bool_t parents;
72727
72728 DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
72729 "(env -> %!dO)",
72730 (void *) thr, (void *) env, (void *) act,
72731 (duk_heaphdr *) name, (duk_heaphdr *) env));
72732
72733 DUK_ASSERT(thr != NULL);
72734 DUK_ASSERT(name != NULL);
72735 /* env and act may be NULL */
72736
72737 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
72738 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72739
72740 parents = 1; /* follow parent chain */
72741 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
72742 if (ref.value) {
72743 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
72744 duk_push_tval(ctx, ref.value);
72745 duk_push_undefined(ctx);
72746 } else {
72747 DUK_ASSERT(ref.holder != NULL);
72748
72749 /* Note: getprop may invoke any getter and invalidate any
72750 * duk_tval pointers, so this must be done first.
72751 */
72752
72753 if (ref.this_binding) {
72754 duk_push_tval(ctx, ref.this_binding);
72755 } else {
72756 duk_push_undefined(ctx);
72757 }
72758
72759 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
72760 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
72761 (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */
72762
72763 /* ref.value, ref.this.binding invalidated here by getprop call */
72764
72765 duk_insert(ctx, -2); /* [this value] -> [value this] */
72766 }
72767
72768 return 1;
72769 } else {
72770 if (throw_flag) {
72771 DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
72772 "identifier '%s' undefined",
72773 (const char *) DUK_HSTRING_GET_DATA(name));
72774 }
72775
72776 return 0;
72777 }
72778}
72779
72780DUK_INTERNAL
72781duk_bool_t duk_js_getvar_envrec(duk_hthread *thr,
72782 duk_hobject *env,
72783 duk_hstring *name,
72784 duk_bool_t throw_flag) {
72785 return duk__getvar_helper(thr, env, NULL, name, throw_flag);
72786}
72787
72788DUK_INTERNAL
72789duk_bool_t duk_js_getvar_activation(duk_hthread *thr,
72790 duk_activation *act,
72791 duk_hstring *name,
72792 duk_bool_t throw_flag) {
72793 DUK_ASSERT(act != NULL);
72794 return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
72795}
72796
72797/*
72798 * PUTVAR
72799 *
72800 * See E5 Sections:
72801 * 11.1.2 Identifier Reference
72802 * 10.3.1 Identifier Resolution
72803 * 11.13.1 Simple Assignment [example of where the Reference is PutValue'd]
72804 * 8.7.2 PutValue (V,W) [see especially step 3.b, undefined -> automatic global in non-strict mode]
72805 * 8.12.4 [[CanPut]] (P)
72806 * 8.12.5 [[Put]] (P)
72807 *
72808 * Note: may invalidate any valstack (or object) duk_tval pointers because
72809 * putting a value may reallocate any object or any valstack. Caller beware.
72810 */
72811
72812DUK_LOCAL
72813void duk__putvar_helper(duk_hthread *thr,
72814 duk_hobject *env,
72815 duk_activation *act,
72816 duk_hstring *name,
72817 duk_tval *val,
72818 duk_bool_t strict) {
72819 duk__id_lookup_result ref;
72820 duk_tval tv_tmp_obj;
72821 duk_tval tv_tmp_key;
72822 duk_bool_t parents;
72823
72824 DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
72825 "(env -> %!dO, val -> %!T)",
72826 (void *) thr, (void *) env, (void *) act,
72827 (duk_heaphdr *) name, (void *) val, (long) strict,
72828 (duk_heaphdr *) env, (duk_tval *) val));
72829
72830 DUK_ASSERT(thr != NULL);
72831 DUK_ASSERT(name != NULL);
72832 DUK_ASSERT(val != NULL);
72833 /* env and act may be NULL */
72834
72835 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
72836 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72837 DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
72838
72839 /*
72840 * In strict mode E5 protects 'eval' and 'arguments' from being
72841 * assigned to (or even declared anywhere). Attempt to do so
72842 * should result in a compile time SyntaxError. See the internal
72843 * design documentation for details.
72844 *
72845 * Thus, we should never come here, run-time, for strict code,
72846 * and name 'eval' or 'arguments'.
72847 */
72848
72849 DUK_ASSERT(!strict ||
72850 (name != DUK_HTHREAD_STRING_EVAL(thr) &&
72851 name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)));
72852
72853 /*
72854 * Lookup variable and update in-place if found.
72855 */
72856
72857 parents = 1; /* follow parent chain */
72858
72859 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
72860 if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
72861 /* Update duk_tval in-place if pointer provided and the
72862 * property is writable. If the property is not writable
72863 * (immutable binding), use duk_hobject_putprop() which
72864 * will respect mutability.
72865 */
72866 duk_tval *tv_val;
72867
72868 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
72869
72870 tv_val = ref.value;
72871 DUK_ASSERT(tv_val != NULL);
72872 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */
72873
72874 /* ref.value and ref.this_binding invalidated here */
72875 } else {
72876 DUK_ASSERT(ref.holder != NULL);
72877
72878 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
72879 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
72880 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
72881
72882 /* ref.value and ref.this_binding invalidated here */
72883 }
72884
72885 return;
72886 }
72887
72888 /*
72889 * Not found: write to global object (non-strict) or ReferenceError
72890 * (strict); see E5 Section 8.7.2, step 3.
72891 */
72892
72893 if (strict) {
72894 DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
72895 DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "identifier not defined");
72896 }
72897
72898 DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
72899
72900 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
72901 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
72902 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0); /* 0 = no throw */
72903
72904 /* NB: 'val' may be invalidated here because put_value may realloc valstack,
72905 * caller beware.
72906 */
72907}
72908
72909DUK_INTERNAL
72910void duk_js_putvar_envrec(duk_hthread *thr,
72911 duk_hobject *env,
72912 duk_hstring *name,
72913 duk_tval *val,
72914 duk_bool_t strict) {
72915 duk__putvar_helper(thr, env, NULL, name, val, strict);
72916}
72917
72918DUK_INTERNAL
72919void duk_js_putvar_activation(duk_hthread *thr,
72920 duk_activation *act,
72921 duk_hstring *name,
72922 duk_tval *val,
72923 duk_bool_t strict) {
72924 DUK_ASSERT(act != NULL);
72925 duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
72926}
72927
72928/*
72929 * DELVAR
72930 *
72931 * See E5 Sections:
72932 * 11.4.1 The delete operator
72933 * 10.2.1.1.5 DeleteBinding (N) [declarative environment record]
72934 * 10.2.1.2.5 DeleteBinding (N) [object environment record]
72935 *
72936 * Variable bindings established inside eval() are deletable (configurable),
72937 * other bindings are not, including variables declared in global level.
72938 * Registers are always non-deletable, and the deletion of other bindings
72939 * is controlled by the configurable flag.
72940 *
72941 * For strict mode code, the 'delete' operator should fail with a compile
72942 * time SyntaxError if applied to identifiers. Hence, no strict mode
72943 * run-time deletion of identifiers should ever happen. This function
72944 * should never be called from strict mode code!
72945 */
72946
72947DUK_LOCAL
72948duk_bool_t duk__delvar_helper(duk_hthread *thr,
72949 duk_hobject *env,
72950 duk_activation *act,
72951 duk_hstring *name) {
72952 duk__id_lookup_result ref;
72953 duk_bool_t parents;
72954
72955 DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
72956 "(env -> %!dO)",
72957 (void *) thr, (void *) env, (void *) act,
72958 (duk_heaphdr *) name, (duk_heaphdr *) env));
72959
72960 DUK_ASSERT(thr != NULL);
72961 DUK_ASSERT(name != NULL);
72962 /* env and act may be NULL */
72963
72964 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72965
72966 parents = 1; /* follow parent chain */
72967
72968 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
72969 if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
72970 /* Identifier found in registers (always non-deletable)
72971 * or declarative environment record and non-configurable.
72972 */
72973 return 0;
72974 }
72975 DUK_ASSERT(ref.holder != NULL);
72976
72977 return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
72978 }
72979
72980 /*
72981 * Not found (even in global object).
72982 *
72983 * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
72984 * step 3.b. In strict mode this case is a compile time SyntaxError so
72985 * we should not come here.
72986 */
72987
72988 DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
72989 "(treated as silent success)",
72990 (duk_heaphdr *) name));
72991 return 1;
72992}
72993
72994#if 0 /*unused*/
72995DUK_INTERNAL
72996duk_bool_t duk_js_delvar_envrec(duk_hthread *thr,
72997 duk_hobject *env,
72998 duk_hstring *name) {
72999 return duk__delvar_helper(thr, env, NULL, name);
73000}
73001#endif
73002
73003DUK_INTERNAL
73004duk_bool_t duk_js_delvar_activation(duk_hthread *thr,
73005 duk_activation *act,
73006 duk_hstring *name) {
73007 DUK_ASSERT(act != NULL);
73008 return duk__delvar_helper(thr, act->lex_env, act, name);
73009}
73010
73011/*
73012 * DECLVAR
73013 *
73014 * See E5 Sections:
73015 * 10.4.3 Entering Function Code
73016 * 10.5 Declaration Binding Instantion
73017 * 12.2 Variable Statement
73018 * 11.1.2 Identifier Reference
73019 * 10.3.1 Identifier Resolution
73020 *
73021 * Variable declaration behavior is mainly discussed in Section 10.5,
73022 * and is not discussed in the execution semantics (Sections 11-13).
73023 *
73024 * Conceptually declarations happen when code (global, eval, function)
73025 * is entered, before any user code is executed. In practice, register-
73026 * bound identifiers are 'declared' automatically (by virtue of being
73027 * allocated to registers with the initial value 'undefined'). Other
73028 * identifiers are declared in the function prologue with this primitive.
73029 *
73030 * Since non-register bindings eventually back to an internal object's
73031 * properties, the 'prop_flags' argument is used to specify binding
73032 * type:
73033 *
73034 * - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false
73035 * - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false
73036 * - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it
73037 * doesn't really matter for internal objects
73038 *
73039 * All bindings are non-deletable mutable bindings except:
73040 *
73041 * - Declarations in eval code (mutable, deletable)
73042 * - 'arguments' binding in strict function code (immutable)
73043 * - Function name binding of a function expression (immutable)
73044 *
73045 * Declarations may go to declarative environment records (always
73046 * so for functions), but may also go to object environment records
73047 * (e.g. global code). The global object environment has special
73048 * behavior when re-declaring a function (but not a variable); see
73049 * E5.1 specification, Section 10.5, step 5.e.
73050 *
73051 * Declarations always go to the 'top-most' environment record, i.e.
73052 * we never check the record chain. It's not an error even if a
73053 * property (even an immutable or non-deletable one) of the same name
73054 * already exists.
73055 *
73056 * If a declared variable already exists, its value needs to be updated
73057 * (if possible). Returns 1 if a PUTVAR needs to be done by the caller;
73058 * otherwise returns 0.
73059 */
73060
73061DUK_LOCAL
73062duk_bool_t duk__declvar_helper(duk_hthread *thr,
73063 duk_hobject *env,
73064 duk_hstring *name,
73065 duk_tval *val,
73066 duk_small_int_t prop_flags,
73067 duk_bool_t is_func_decl) {
73068 duk_context *ctx = (duk_context *) thr;
73069 duk_hobject *holder;
73070 duk_bool_t parents;
73071 duk__id_lookup_result ref;
73072 duk_tval *tv;
73073
73074 DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld "
73075 "(env -> %!iO)",
73076 (void *) thr, (void *) env, (duk_heaphdr *) name,
73077 (duk_tval *) val, (unsigned long) prop_flags,
73078 (unsigned int) is_func_decl, (duk_heaphdr *) env));
73079
73080 DUK_ASSERT(thr != NULL);
73081 DUK_ASSERT(env != NULL);
73082 DUK_ASSERT(name != NULL);
73083 DUK_ASSERT(val != NULL);
73084
73085 /* Note: in strict mode the compiler should reject explicit
73086 * declaration of 'eval' or 'arguments'. However, internal
73087 * bytecode may declare 'arguments' in the function prologue.
73088 * We don't bother checking (or asserting) for these now.
73089 */
73090
73091 /* Note: val is a stable duk_tval pointer. The caller makes
73092 * a value copy into its stack frame, so 'tv_val' is not subject
73093 * to side effects here.
73094 */
73095
73096 /*
73097 * Check whether already declared.
73098 *
73099 * We need to check whether the binding exists in the environment
73100 * without walking its parents. However, we still need to check
73101 * register-bound identifiers and the prototype chain of an object
73102 * environment target object.
73103 */
73104
73105 parents = 0; /* just check 'env' */
73106 if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
73107 duk_int_t e_idx;
73108 duk_int_t h_idx;
73109 duk_small_int_t flags;
73110
73111 /*
73112 * Variable already declared, ignore re-declaration.
73113 * The only exception is the updated behavior of E5.1 for
73114 * global function declarations, E5.1 Section 10.5, step 5.e.
73115 * This behavior does not apply to global variable declarations.
73116 */
73117
73118 if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
73119 DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring"));
73120 return 1; /* 1 -> needs a PUTVAR */
73121 }
73122
73123 /*
73124 * Special behavior in E5.1.
73125 *
73126 * Note that even though parents == 0, the conflicting property
73127 * may be an inherited property (currently our global object's
73128 * prototype is Object.prototype). Step 5.e first operates on
73129 * the existing property (which is potentially in an ancestor)
73130 * and then defines a new property in the global object (and
73131 * never modifies the ancestor).
73132 *
73133 * Also note that this logic would become even more complicated
73134 * if the conflicting property might be a virtual one. Object
73135 * prototype has no virtual properties, though.
73136 *
73137 * XXX: this is now very awkward, rework.
73138 */
73139
73140 DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, "
73141 "updated E5.1 processing"));
73142
73143 DUK_ASSERT(ref.holder != NULL);
73144 holder = ref.holder;
73145
73146 /* holder will be set to the target object, not the actual object
73147 * where the property was found (see duk__get_identifier_reference()).
73148 */
73149 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL);
73150 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */
73151
73152 /* XXX: use a helper for prototype traversal; no loop check here */
73153 /* must be found: was found earlier, and cannot be inherited */
73154 for (;;) {
73155 DUK_ASSERT(holder != NULL);
73156 duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx);
73157 if (e_idx >= 0) {
73158 break;
73159 }
73160 /* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
73161 * asserted above.
73162 */
73163 holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder);
73164 }
73165 DUK_ASSERT(holder != NULL);
73166 DUK_ASSERT(e_idx >= 0);
73167 /* SCANBUILD: scan-build produces a NULL pointer dereference warning
73168 * below; it never actually triggers because holder is actually never
73169 * NULL.
73170 */
73171
73172 /* ref.holder is global object, holder is the object with the
73173 * conflicting property.
73174 */
73175
73176 flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx);
73177 if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
73178 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
73179 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
73180 "accessor -> reject"));
73181 goto fail_existing_attributes;
73182 }
73183 if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
73184 (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
73185 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
73186 "plain property which is not writable and "
73187 "enumerable -> reject"));
73188 goto fail_existing_attributes;
73189 }
73190
73191 DUK_DDD(DUK_DDDPRINT("existing property is not configurable but "
73192 "is plain, enumerable, and writable -> "
73193 "allow redeclaration"));
73194 }
73195
73196 if (holder == ref.holder) {
73197 /* XXX: if duk_hobject_define_property_internal() was updated
73198 * to handle a pre-existing accessor property, this would be
73199 * a simple call (like for the ancestor case).
73200 */
73201 DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself"));
73202
73203 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
73204 duk_hobject *tmp;
73205
73206 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
73207 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
73208 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
73209 DUK_UNREF(tmp);
73210 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
73211 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
73212 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
73213 DUK_UNREF(tmp);
73214 } else {
73215 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
73216 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);
73217 }
73218
73219 /* Here val would be potentially invalid if we didn't make
73220 * a value copy at the caller.
73221 */
73222
73223 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
73224 DUK_TVAL_SET_TVAL(tv, val);
73225 DUK_TVAL_INCREF(thr, tv);
73226 DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags);
73227
73228 DUK_DDD(DUK_DDDPRINT("updated global binding, final result: "
73229 "value -> %!T, prop_flags=0x%08lx",
73230 (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx),
73231 (unsigned long) prop_flags));
73232 } else {
73233 DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
73234
73235 DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
73236 duk_push_tval(ctx, val);
73237 duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
73238 }
73239
73240 return 0;
73241 }
73242
73243 /*
73244 * Not found (in registers or record objects). Declare
73245 * to current variable environment.
73246 */
73247
73248 /*
73249 * Get holder object
73250 */
73251
73252 if (DUK_HOBJECT_IS_DECENV(env)) {
73253 holder = env;
73254 } else {
73255 DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env));
73256
73257 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
73258 DUK_ASSERT(tv != NULL);
73259 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
73260 holder = DUK_TVAL_GET_OBJECT(tv);
73261 DUK_ASSERT(holder != NULL);
73262 }
73263
73264 /*
73265 * Define new property
73266 *
73267 * Note: this may fail if the holder is not extensible.
73268 */
73269
73270 /* XXX: this is awkward as we use an internal method which doesn't handle
73271 * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]]
73272 * or Object.defineProperty() here.
73273 */
73274
73275 if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
73276 goto fail_not_extensible;
73277 }
73278
73279 duk_push_hobject(ctx, holder);
73280 duk_push_hstring(ctx, name);
73281 duk_push_tval(ctx, val);
73282 duk_xdef_prop(ctx, -3, prop_flags); /* [holder name val] -> [holder] */
73283 duk_pop(ctx);
73284
73285 return 0;
73286
73287 fail_existing_attributes:
73288 fail_not_extensible:
73289 DUK_ERROR_TYPE(thr, "declaration failed");
73290 return 0;
73291}
73292
73293DUK_INTERNAL
73294duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
73295 duk_activation *act,
73296 duk_hstring *name,
73297 duk_tval *val,
73298 duk_small_int_t prop_flags,
73299 duk_bool_t is_func_decl) {
73300 duk_hobject *env;
73301 duk_tval tv_val_copy;
73302 duk_size_t act_off;
73303
73304 DUK_ASSERT(act != NULL);
73305 act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
73306
73307 /*
73308 * Make a value copy of the input val. This ensures that
73309 * side effects cannot invalidate the pointer.
73310 */
73311
73312 DUK_TVAL_SET_TVAL(&tv_val_copy, val);
73313 val = &tv_val_copy;
73314
73315 /*
73316 * Delayed env creation check
73317 */
73318
73319 if (!act->var_env) {
73320 DUK_ASSERT(act->lex_env == NULL);
73321 duk_js_init_activation_environment_records_delayed(thr, act);
73322 act = (duk_activation *) ((duk_uint8_t *) thr->callstack + act_off);
73323 }
73324 DUK_ASSERT(act->lex_env != NULL);
73325 DUK_ASSERT(act->var_env != NULL);
73326
73327 env = act->var_env;
73328 DUK_ASSERT(env != NULL);
73329 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
73330
73331 return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
73332}
73333#line 1 "duk_lexer.c"
73334/*
73335 * Lexer for source files, ToNumber() string conversions, RegExp expressions,
73336 * and JSON.
73337 *
73338 * Provides a stream of Ecmascript tokens from an UTF-8/CESU-8 buffer. The
73339 * caller can also rewind the token stream into a certain position which is
73340 * needed by the compiler part for multi-pass scanning. Tokens are
73341 * represented as duk_token structures, and contain line number information.
73342 * Token types are identified with DUK_TOK_* defines.
73343 *
73344 * Characters are decoded into a fixed size lookup window consisting of
73345 * decoded Unicode code points, with window positions past the end of the
73346 * input filled with an invalid codepoint (-1). The tokenizer can thus
73347 * perform multiple character lookups efficiently and with few sanity
73348 * checks (such as access outside the end of the input), which keeps the
73349 * tokenization code small at the cost of performance.
73350 *
73351 * Character data in tokens, such as identifier names and string literals,
73352 * is encoded into CESU-8 format on-the-fly while parsing the token in
73353 * question. The string data is made reachable to garbage collection by
73354 * placing the token-related values in value stack entries allocated for
73355 * this purpose by the caller. The characters exist in Unicode code point
73356 * form only in the fixed size lookup window, which keeps character data
73357 * expansion (of especially ASCII data) low.
73358 *
73359 * Token parsing supports the full range of Unicode characters as described
73360 * in the E5 specification. Parsing has been optimized for ASCII characters
73361 * because ordinary Ecmascript code consists almost entirely of ASCII
73362 * characters. Matching of complex Unicode codepoint sets (such as in the
73363 * IdentifierStart and IdentifierPart productions) is optimized for size,
73364 * and is done using a linear scan of a bit-packed list of ranges. This is
73365 * very slow, but should never be entered unless the source code actually
73366 * contains Unicode characters.
73367 *
73368 * Ecmascript tokenization is partially context sensitive. First,
73369 * additional future reserved words are recognized in strict mode (see E5
73370 * Section 7.6.1.2). Second, a forward slash character ('/') can be
73371 * recognized either as starting a RegExp literal or as a division operator,
73372 * depending on context. The caller must provide necessary context flags
73373 * when requesting a new token.
73374 *
73375 * Future work:
73376 *
73377 * * Make line number tracking optional, as it consumes space.
73378 *
73379 * * Add a feature flag for disabling UTF-8 decoding of input, as most
73380 * source code is ASCII. Because of Unicode escapes written in ASCII,
73381 * this does not allow Unicode support to be removed from e.g.
73382 * duk_unicode_is_identifier_start() nor does it allow removal of CESU-8
73383 * encoding of e.g. string literals.
73384 *
73385 * * Add a feature flag for disabling Unicode compliance of e.g. identifier
73386 * names. This allows for a build more than a kilobyte smaller, because
73387 * Unicode ranges needed by duk_unicode_is_identifier_start() and
73388 * duk_unicode_is_identifier_part() can be dropped. String literals
73389 * should still be allowed to contain escaped Unicode, so this still does
73390 * not allow removal of CESU-8 encoding of e.g. string literals.
73391 *
73392 * * Character lookup tables for codepoints above BMP could be stripped.
73393 *
73394 * * Strictly speaking, E5 specification requires that source code consists
73395 * of 16-bit code units, and if not, must be conceptually converted to
73396 * that format first. The current lexer processes Unicode code points
73397 * and allows characters outside the BMP. These should be converted to
73398 * surrogate pairs while reading the source characters into the window,
73399 * not after tokens have been formed (as is done now). However, the fix
73400 * is not trivial because two characters are decoded from one codepoint.
73401 *
73402 * * Optimize for speed as well as size. Large if-else ladders are (at
73403 * least potentially) slow.
73404 */
73405
73406/* include removed: duk_internal.h */
73407
73408/*
73409 * Various defines and file specific helper macros
73410 */
73411
73412#define DUK__MAX_RE_DECESC_DIGITS 9
73413#define DUK__MAX_RE_QUANT_DIGITS 9 /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */
73414
73415/* whether to use macros or helper function depends on call count */
73416#define DUK__ISDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9)
73417#define DUK__ISHEXDIGIT(x) duk__is_hex_digit((x))
73418#define DUK__ISOCTDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7)
73419#define DUK__ISDIGIT03(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3)
73420#define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7)
73421
73422/* lexer character window helpers */
73423#define DUK__LOOKUP(lex_ctx,index) ((lex_ctx)->window[(index)].codepoint)
73424#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_bytes((lex_ctx), (count) * sizeof(duk_lexer_codepoint))
73425#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count))
73426#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx))
73427#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
73428
73429/* lookup shorthands (note: assume context variable is named 'lex_ctx') */
73430#define DUK__L0() DUK__LOOKUP(lex_ctx, 0)
73431#define DUK__L1() DUK__LOOKUP(lex_ctx, 1)
73432#define DUK__L2() DUK__LOOKUP(lex_ctx, 2)
73433#define DUK__L3() DUK__LOOKUP(lex_ctx, 3)
73434#define DUK__L4() DUK__LOOKUP(lex_ctx, 4)
73435#define DUK__L5() DUK__LOOKUP(lex_ctx, 5)
73436
73437/* packed advance/token number macro used by multiple functions */
73438#define DUK__ADVTOK(advbytes,tok) ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok))
73439
73440/*
73441 * Advance lookup window by N characters, filling in new characters as
73442 * necessary. After returning caller is guaranteed a character window of
73443 * at least DUK_LEXER_WINDOW_SIZE characters.
73444 *
73445 * The main function duk__advance_bytes() is called at least once per every
73446 * token so it has a major lexer/compiler performance impact. There are two
73447 * variants for the main duk__advance_bytes() algorithm: a sliding window
73448 * approach which is slightly faster at the cost of larger code footprint,
73449 * and a simple copying one.
73450 *
73451 * Decoding directly from the source string would be another lexing option.
73452 * But the lookup window based approach has the advantage of hiding the
73453 * source string and its encoding effectively which gives more flexibility
73454 * going forward to e.g. support chunked streaming of source from flash.
73455 *
73456 * Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to
73457 * U+10FFFF, causing an error if the input is unparseable. Leniency means:
73458 *
73459 * * Unicode code point validation is intentionally not performed,
73460 * except to check that the codepoint does not exceed 0x10ffff.
73461 *
73462 * * In particular, surrogate pairs are allowed and not combined, which
73463 * allows source files to represent all SourceCharacters with CESU-8.
73464 * Broken surrogate pairs are allowed, as Ecmascript does not mandate
73465 * their validation.
73466 *
73467 * * Allow non-shortest UTF-8 encodings.
73468 *
73469 * Leniency here causes few security concerns because all character data is
73470 * decoded into Unicode codepoints before lexer processing, and is then
73471 * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with
73472 * a compiler option. However, Ecmascript source characters include -all-
73473 * 16-bit unsigned integer codepoints, so leniency seems to be appropriate.
73474 *
73475 * Note that codepoints above the BMP are not strictly SourceCharacters,
73476 * but the lexer still accepts them as such. Before ending up in a string
73477 * or an identifier name, codepoints above BMP are converted into surrogate
73478 * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as
73479 * expected by Ecmascript.
73480 *
73481 * An alternative approach to dealing with invalid or partial sequences
73482 * would be to skip them and replace them with e.g. the Unicode replacement
73483 * character U+FFFD. This has limited utility because a replacement character
73484 * will most likely cause a parse error, unless it occurs inside a string.
73485 * Further, Ecmascript source is typically pure ASCII.
73486 *
73487 * See:
73488 *
73489 * http://en.wikipedia.org/wiki/UTF-8
73490 * http://en.wikipedia.org/wiki/CESU-8
73491 * http://tools.ietf.org/html/rfc3629
73492 * http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
73493 *
73494 * Future work:
73495 *
73496 * * Reject other invalid Unicode sequences (see Wikipedia entry for examples)
73497 * in strict UTF-8 mode.
73498 *
73499 * * Size optimize. An attempt to use a 16-byte lookup table for the first
73500 * byte resulted in a code increase though.
73501 *
73502 * * Is checking against maximum 0x10ffff really useful? 4-byte encoding
73503 * imposes a certain limit anyway.
73504 *
73505 * * Support chunked streaming of source code. Can be implemented either
73506 * by streaming chunks of bytes or chunks of codepoints.
73507 */
73508
73509#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
73510DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) {
73511 duk_lexer_codepoint *cp, *cp_end;
73512 duk_ucodepoint_t x;
73513 duk_small_uint_t contlen;
73514 const duk_uint8_t *p, *p_end;
73515#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73516 duk_ucodepoint_t mincp;
73517#endif
73518 duk_int_t input_line;
73519
73520 /* Use temporaries and update lex_ctx only when finished. */
73521 input_line = lex_ctx->input_line;
73522 p = lex_ctx->input + lex_ctx->input_offset;
73523 p_end = lex_ctx->input + lex_ctx->input_length;
73524
73525 cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes);
73526 cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE;
73527
73528 for (; cp != cp_end; cp++) {
73529 cp->offset = (duk_size_t) (p - lex_ctx->input);
73530 cp->line = input_line;
73531
73532 /* XXX: potential issue with signed pointers, p_end < p. */
73533 if (DUK_UNLIKELY(p >= p_end)) {
73534 /* If input_offset were assigned a negative value, it would
73535 * result in a large positive value. Most likely it would be
73536 * larger than input_length and be caught here. In any case
73537 * no memory unsafe behavior would happen.
73538 */
73539 cp->codepoint = -1;
73540 continue;
73541 }
73542
73543 x = (duk_ucodepoint_t) (*p++);
73544
73545 /* Fast path. */
73546
73547 if (DUK_LIKELY(x < 0x80UL)) {
73548 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
73549 if (DUK_UNLIKELY(x <= 0x000dUL)) {
73550 if ((x == 0x000aUL) ||
73551 ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) {
73552 /* lookup for 0x000a above assumes shortest encoding now */
73553
73554 /* E5 Section 7.3, treat the following as newlines:
73555 * LF
73556 * CR [not followed by LF]
73557 * LS
73558 * PS
73559 *
73560 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
73561 * the line number.
73562 */
73563 input_line++;
73564 }
73565 }
73566
73567 cp->codepoint = (duk_codepoint_t) x;
73568 continue;
73569 }
73570
73571 /* Slow path. */
73572
73573 if (x < 0xc0UL) {
73574 /* 10xx xxxx -> invalid */
73575 goto error_encoding;
73576 } else if (x < 0xe0UL) {
73577 /* 110x xxxx 10xx xxxx */
73578 contlen = 1;
73579#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73580 mincp = 0x80UL;
73581#endif
73582 x = x & 0x1fUL;
73583 } else if (x < 0xf0UL) {
73584 /* 1110 xxxx 10xx xxxx 10xx xxxx */
73585 contlen = 2;
73586#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73587 mincp = 0x800UL;
73588#endif
73589 x = x & 0x0fUL;
73590 } else if (x < 0xf8UL) {
73591 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
73592 contlen = 3;
73593#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73594 mincp = 0x10000UL;
73595#endif
73596 x = x & 0x07UL;
73597 } else {
73598 /* no point in supporting encodings of 5 or more bytes */
73599 goto error_encoding;
73600 }
73601
73602 DUK_ASSERT(p_end >= p);
73603 if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) {
73604 goto error_clipped;
73605 }
73606
73607 while (contlen > 0) {
73608 duk_small_uint_t y;
73609 y = *p++;
73610 if ((y & 0xc0U) != 0x80U) {
73611 /* check that byte has the form 10xx xxxx */
73612 goto error_encoding;
73613 }
73614 x = x << 6;
73615 x += y & 0x3fUL;
73616 contlen--;
73617 }
73618
73619 /* check final character validity */
73620
73621 if (x > 0x10ffffUL) {
73622 goto error_encoding;
73623 }
73624#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73625 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
73626 goto error_encoding;
73627 }
73628#endif
73629
73630 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
73631 if ((x == 0x2028UL) || (x == 0x2029UL)) {
73632 input_line++;
73633 }
73634
73635 cp->codepoint = (duk_codepoint_t) x;
73636 }
73637
73638 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
73639 lex_ctx->input_line = input_line;
73640 return;
73641
73642 error_clipped: /* clipped codepoint */
73643 error_encoding: /* invalid codepoint encoding or codepoint */
73644 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
73645 lex_ctx->input_line = input_line;
73646
73647 DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
73648}
73649
73650DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
73651 duk_small_uint_t used_bytes, avail_bytes;
73652
73653 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
73654 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
73655 DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer);
73656 DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE);
73657 DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint));
73658
73659 /* Zero 'count' is also allowed to make call sites easier.
73660 * Arithmetic in bytes generates better code in GCC.
73661 */
73662
73663 lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes); /* avoid multiply */
73664 used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer);
73665 avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes;
73666 if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) {
73667 /* Not enough data to provide a full window, so "scroll" window to
73668 * start of buffer and fill up the rest.
73669 */
73670 DUK_MEMMOVE((void *) lex_ctx->buffer,
73671 (const void *) lex_ctx->window,
73672 (size_t) avail_bytes);
73673 lex_ctx->window = lex_ctx->buffer;
73674 duk__fill_lexer_buffer(lex_ctx, avail_bytes);
73675 }
73676}
73677
73678DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
73679 lex_ctx->window = lex_ctx->buffer;
73680 duk__fill_lexer_buffer(lex_ctx, 0);
73681}
73682#else /* DUK_USE_LEXER_SLIDING_WINDOW */
73683DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
73684 duk_ucodepoint_t x;
73685 duk_small_uint_t len;
73686 duk_small_uint_t i;
73687 const duk_uint8_t *p;
73688#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73689 duk_ucodepoint_t mincp;
73690#endif
73691 duk_size_t input_offset;
73692
73693 input_offset = lex_ctx->input_offset;
73694 if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) {
73695 /* If input_offset were assigned a negative value, it would
73696 * result in a large positive value. Most likely it would be
73697 * larger than input_length and be caught here. In any case
73698 * no memory unsafe behavior would happen.
73699 */
73700 return -1;
73701 }
73702
73703 p = lex_ctx->input + input_offset;
73704 x = (duk_ucodepoint_t) (*p);
73705
73706 if (DUK_LIKELY(x < 0x80UL)) {
73707 /* 0xxx xxxx -> fast path */
73708
73709 /* input offset tracking */
73710 lex_ctx->input_offset++;
73711
73712 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
73713 if (DUK_UNLIKELY(x <= 0x000dUL)) {
73714 if ((x == 0x000aUL) ||
73715 ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length ||
73716 lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) {
73717 /* lookup for 0x000a above assumes shortest encoding now */
73718
73719 /* E5 Section 7.3, treat the following as newlines:
73720 * LF
73721 * CR [not followed by LF]
73722 * LS
73723 * PS
73724 *
73725 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
73726 * the line number.
73727 */
73728 lex_ctx->input_line++;
73729 }
73730 }
73731
73732 return (duk_codepoint_t) x;
73733 }
73734
73735 /* Slow path. */
73736
73737 if (x < 0xc0UL) {
73738 /* 10xx xxxx -> invalid */
73739 goto error_encoding;
73740 } else if (x < 0xe0UL) {
73741 /* 110x xxxx 10xx xxxx */
73742 len = 2;
73743#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73744 mincp = 0x80UL;
73745#endif
73746 x = x & 0x1fUL;
73747 } else if (x < 0xf0UL) {
73748 /* 1110 xxxx 10xx xxxx 10xx xxxx */
73749 len = 3;
73750#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73751 mincp = 0x800UL;
73752#endif
73753 x = x & 0x0fUL;
73754 } else if (x < 0xf8UL) {
73755 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
73756 len = 4;
73757#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73758 mincp = 0x10000UL;
73759#endif
73760 x = x & 0x07UL;
73761 } else {
73762 /* no point in supporting encodings of 5 or more bytes */
73763 goto error_encoding;
73764 }
73765
73766 DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset);
73767 if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) {
73768 goto error_clipped;
73769 }
73770
73771 p++;
73772 for (i = 1; i < len; i++) {
73773 duk_small_uint_t y;
73774 y = *p++;
73775 if ((y & 0xc0U) != 0x80U) {
73776 /* check that byte has the form 10xx xxxx */
73777 goto error_encoding;
73778 }
73779 x = x << 6;
73780 x += y & 0x3fUL;
73781 }
73782
73783 /* check final character validity */
73784
73785 if (x > 0x10ffffUL) {
73786 goto error_encoding;
73787 }
73788#if defined(DUK_USE_STRICT_UTF8_SOURCE)
73789 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
73790 goto error_encoding;
73791 }
73792#endif
73793
73794 /* input offset tracking */
73795 lex_ctx->input_offset += len;
73796
73797 /* line tracking */
73798 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
73799 if ((x == 0x2028UL) || (x == 0x2029UL)) {
73800 lex_ctx->input_line++;
73801 }
73802
73803 return (duk_codepoint_t) x;
73804
73805 error_clipped: /* clipped codepoint */
73806 error_encoding: /* invalid codepoint encoding or codepoint */
73807 DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
73808 return 0;
73809}
73810
73811DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
73812 duk_small_uint_t keep_bytes;
73813 duk_lexer_codepoint *cp, *cp_end;
73814
73815 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
73816 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
73817
73818 /* Zero 'count' is also allowed to make call sites easier. */
73819
73820 keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes;
73821 DUK_MEMMOVE((void *) lex_ctx->window,
73822 (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes),
73823 (size_t) keep_bytes);
73824
73825 cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes);
73826 cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE;
73827 for (; cp != cp_end; cp++) {
73828 cp->offset = lex_ctx->input_offset;
73829 cp->line = lex_ctx->input_line;
73830 cp->codepoint = duk__read_char(lex_ctx);
73831 }
73832}
73833
73834DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
73835 /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */
73836 duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)); /* fill window */
73837}
73838#endif /* DUK_USE_LEXER_SLIDING_WINDOW */
73839
73840/*
73841 * (Re)initialize the temporary byte buffer. May be called extra times
73842 * with little impact.
73843 */
73844
73845DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) {
73846 /* Reuse buffer as is unless buffer has grown large. */
73847 if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) {
73848 /* Keep current size */
73849 } else {
73850 duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT);
73851 }
73852
73853 DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf);
73854}
73855
73856/*
73857 * Append a Unicode codepoint to the temporary byte buffer. Performs
73858 * CESU-8 surrogate pair encoding for codepoints above the BMP.
73859 * Existing surrogate pairs are allowed and also encoded into CESU-8.
73860 */
73861
73862DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
73863 /*
73864 * Since character data is only generated by decoding the source or by
73865 * the compiler itself, we rely on the input codepoints being correct
73866 * and avoid a check here.
73867 *
73868 * Character data can also come here through decoding of Unicode
73869 * escapes ("\udead\ubeef") so all 16-but unsigned values can be
73870 * present, even when the source file itself is strict UTF-8.
73871 */
73872
73873 DUK_ASSERT(x >= 0 && x <= 0x10ffff);
73874
73875 DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x);
73876}
73877
73878/*
73879 * Intern the temporary byte buffer into a valstack slot
73880 * (in practice, slot1 or slot2).
73881 */
73882
73883DUK_LOCAL void duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
73884 duk_context *ctx = (duk_context *) lex_ctx->thr;
73885
73886 DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
73887
73888 DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
73889 duk_replace(ctx, valstack_idx);
73890}
73891
73892/*
73893 * Init lexer context
73894 */
73895
73896DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
73897 DUK_ASSERT(lex_ctx != NULL);
73898
73899 DUK_MEMZERO(lex_ctx, sizeof(*lex_ctx));
73900#if defined(DUK_USE_EXPLICIT_NULL_INIT)
73901#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
73902 lex_ctx->window = NULL;
73903#endif
73904 lex_ctx->thr = NULL;
73905 lex_ctx->input = NULL;
73906 lex_ctx->buf = NULL;
73907#endif
73908}
73909
73910/*
73911 * Set lexer input position and reinitialize lookup window.
73912 */
73913
73914/* NB: duk_lexer_getpoint() is a macro only */
73915
73916DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
73917 DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */
73918 DUK_ASSERT(pt->line >= 1);
73919 lex_ctx->input_offset = pt->offset;
73920 lex_ctx->input_line = pt->line;
73921 duk__init_lexer_window(lex_ctx);
73922}
73923
73924/*
73925 * Lexing helpers
73926 */
73927
73928/* numeric value of a hex digit (also covers octal and decimal digits) */
73929DUK_LOCAL duk_codepoint_t duk__hexval(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
73930 duk_small_int_t t;
73931
73932 /* Here 'x' is a Unicode codepoint */
73933 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
73934 t = duk_hex_dectab[x];
73935 if (DUK_LIKELY(t >= 0)) {
73936 return t;
73937 }
73938 }
73939
73940 /* Throwing an error this deep makes the error rather vague, but
73941 * saves hundreds of bytes of code.
73942 */
73943 DUK_ERROR_SYNTAX(lex_ctx->thr, "decode error");
73944 return 0;
73945}
73946
73947/* having this as a separate function provided a size benefit */
73948DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) {
73949 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
73950 return (duk_hex_dectab[x] >= 0);
73951 }
73952 return 0;
73953}
73954
73955DUK_LOCAL duk_codepoint_t duk__decode_hexesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
73956 /* validation performed by duk__hexval */
73957 return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 4) |
73958 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint));
73959}
73960
73961DUK_LOCAL duk_codepoint_t duk__decode_uniesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
73962 /* validation performed by duk__hexval */
73963 return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 12) |
73964 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint) << 8) |
73965 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 2].codepoint) << 4) |
73966 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 3].codepoint));
73967}
73968
73969/*
73970 * Parse Ecmascript source InputElementDiv or InputElementRegExp
73971 * (E5 Section 7), skipping whitespace, comments, and line terminators.
73972 *
73973 * Possible results are:
73974 * (1) a token
73975 * (2) a line terminator (skipped)
73976 * (3) a comment (skipped)
73977 * (4) EOF
73978 *
73979 * White space is automatically skipped from the current position (but
73980 * not after the input element). If input has already ended, returns
73981 * DUK_TOK_EOF indefinitely. If a parse error occurs, uses an DUK_ERROR()
73982 * macro call (and hence a longjmp through current heap longjmp context).
73983 * Comments and line terminator tokens are automatically skipped.
73984 *
73985 * The input element being matched is determined by regexp_mode; if set,
73986 * parses a InputElementRegExp, otherwise a InputElementDiv. The
73987 * difference between these are handling of productions starting with a
73988 * forward slash.
73989 *
73990 * If strict_mode is set, recognizes additional future reserved words
73991 * specific to strict mode, and refuses to parse octal literals.
73992 *
73993 * The matching strategy below is to (currently) use a six character
73994 * lookup window to quickly determine which production is the -longest-
73995 * matching one, and then parse that. The top-level if-else clauses
73996 * match the first character, and the code blocks for each clause
73997 * handle -all- alternatives for that first character. Ecmascript
73998 * specification uses the "longest match wins" semantics, so the order
73999 * of the if-clauses matters.
74000 *
74001 * Misc notes:
74002 *
74003 * * Ecmascript numeric literals do not accept a sign character.
74004 * Consequently e.g. "-1.0" is parsed as two tokens: a negative
74005 * sign and a positive numeric literal. The compiler performs
74006 * the negation during compilation, so this has no adverse impact.
74007 *
74008 * * There is no token for "undefined": it is just a value available
74009 * from the global object (or simply established by doing a reference
74010 * to an undefined value).
74011 *
74012 * * Some contexts want Identifier tokens, which are IdentifierNames
74013 * excluding reserved words, while some contexts want IdentifierNames
74014 * directly. In the latter case e.g. "while" is interpreted as an
74015 * identifier name, not a DUK_TOK_WHILE token. The solution here is
74016 * to provide both token types: DUK_TOK_WHILE goes to 't' while
74017 * DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains
74018 * the identifier / keyword name.
74019 *
74020 * * Directive prologue needs to identify string literals such as
74021 * "use strict" and 'use strict', which are sensitive to line
74022 * continuations and escape sequences. For instance, "use\u0020strict"
74023 * is a valid directive but is distinct from "use strict". The solution
74024 * here is to decode escapes while tokenizing, but to keep track of the
74025 * number of escapes. Directive detection can then check that the
74026 * number of escapes is zero.
74027 *
74028 * * Multi-line comments with one or more internal LineTerminator are
74029 * treated like a line terminator to comply with automatic semicolon
74030 * insertion.
74031 */
74032
74033DUK_INTERNAL
74034void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
74035 duk_token *out_token,
74036 duk_bool_t strict_mode,
74037 duk_bool_t regexp_mode) {
74038 duk_codepoint_t x; /* temporary, must be signed and 32-bit to hold Unicode code points */
74039 duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end,
74040 * init is unnecessary but suppresses "may be used uninitialized" warnings.
74041 */
74042 duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */
74043
74044 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
74045 DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
74046 return; /* unreachable */
74047 }
74048
74049 out_token->t = DUK_TOK_EOF;
74050 out_token->t_nores = -1; /* marker: copy t if not changed */
74051#if 0 /* not necessary to init, disabled for faster parsing */
74052 out_token->num = DUK_DOUBLE_NAN;
74053 out_token->str1 = NULL;
74054 out_token->str2 = NULL;
74055#endif
74056 out_token->num_escapes = 0;
74057 /* out_token->lineterm set by caller */
74058
74059 /* This would be nice, but parsing is faster without resetting the
74060 * value slots. The only side effect is that references to temporary
74061 * string values may linger until lexing is finished; they're then
74062 * freed normally.
74063 */
74064#if 0
74065 duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74066 duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
74067#endif
74068
74069 /* 'advtok' indicates how much to advance and which token id to assign
74070 * at the end. This shared functionality minimizes code size. All
74071 * code paths are required to set 'advtok' to some value, so no default
74072 * init value is used. Code paths calling DUK_ERROR() never return so
74073 * they don't need to set advtok.
74074 */
74075
74076 /*
74077 * Matching order:
74078 *
74079 * Punctuator first chars, also covers comments, regexps
74080 * LineTerminator
74081 * Identifier or reserved word, also covers null/true/false literals
74082 * NumericLiteral
74083 * StringLiteral
74084 * EOF
74085 *
74086 * The order does not matter as long as the longest match is
74087 * always correctly identified. There are order dependencies
74088 * in the clauses, so it's not trivial to convert to a switch.
74089 */
74090
74091 restart_lineupdate:
74092 out_token->start_line = lex_ctx->window[0].line;
74093
74094 restart:
74095 out_token->start_offset = lex_ctx->window[0].offset;
74096
74097 x = DUK__L0();
74098
74099 switch (x) {
74100 case DUK_ASC_SPACE:
74101 case DUK_ASC_HT: /* fast paths for space and tab */
74102 DUK__ADVANCECHARS(lex_ctx, 1);
74103 goto restart;
74104 case DUK_ASC_LF: /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */
74105 DUK__ADVANCECHARS(lex_ctx, 1);
74106 got_lineterm = 1;
74107 goto restart_lineupdate;
74108 case DUK_ASC_SLASH: /* '/' */
74109 if (DUK__L1() == '/') {
74110 /*
74111 * E5 Section 7.4, allow SourceCharacter (which is any 16-bit
74112 * code point).
74113 */
74114
74115 /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */
74116 for (;;) {
74117 x = DUK__L0();
74118 if (x < 0 || duk_unicode_is_line_terminator(x)) {
74119 break;
74120 }
74121 DUK__ADVANCECHARS(lex_ctx, 1);
74122 }
74123 goto restart; /* line terminator will be handled on next round */
74124 } else if (DUK__L1() == '*') {
74125 /*
74126 * E5 Section 7.4. If the multi-line comment contains a newline,
74127 * it is treated like a single line terminator for automatic
74128 * semicolon insertion.
74129 */
74130
74131 duk_bool_t last_asterisk = 0;
74132 DUK__ADVANCECHARS(lex_ctx, 2);
74133 for (;;) {
74134 x = DUK__L0();
74135 if (x < 0) {
74136 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in multiline comment");
74137 }
74138 DUK__ADVANCECHARS(lex_ctx, 1);
74139 if (last_asterisk && x == '/') {
74140 break;
74141 }
74142 if (duk_unicode_is_line_terminator(x)) {
74143 got_lineterm = 1;
74144 }
74145 last_asterisk = (x == '*');
74146 }
74147 goto restart_lineupdate;
74148 } else if (regexp_mode) {
74149#if defined(DUK_USE_REGEXP_SUPPORT)
74150 /*
74151 * "/" followed by something in regexp mode. See E5 Section 7.8.5.
74152 *
74153 * RegExp parsing is a bit complex. First, the regexp body is delimited
74154 * by forward slashes, but the body may also contain forward slashes as
74155 * part of an escape sequence or inside a character class (delimited by
74156 * square brackets). A mini state machine is used to implement these.
74157 *
74158 * Further, an early (parse time) error must be thrown if the regexp
74159 * would cause a run-time error when used in the expression new RegExp(...).
74160 * Parsing here simply extracts the (candidate) regexp, and also accepts
74161 * invalid regular expressions (which are delimited properly). The caller
74162 * (compiler) must perform final validation and regexp compilation.
74163 *
74164 * RegExp first char may not be '/' (single line comment) or '*' (multi-
74165 * line comment). These have already been checked above, so there is no
74166 * need below for special handling of the first regexp character as in
74167 * the E5 productions.
74168 *
74169 * About unicode escapes within regexp literals:
74170 *
74171 * E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes.
74172 * However, Section 6 states that regexps accept the escapes,
74173 * see paragraph starting with "In string literals...".
74174 * The regexp grammar, which sees the decoded regexp literal
74175 * (after lexical parsing) DOES have a \uHHHH unicode escape.
74176 * So, for instance:
74177 *
74178 * /\u1234/
74179 *
74180 * should first be parsed by the lexical grammar as:
74181 *
74182 * '\' 'u' RegularExpressionBackslashSequence
74183 * '1' RegularExpressionNonTerminator
74184 * '2' RegularExpressionNonTerminator
74185 * '3' RegularExpressionNonTerminator
74186 * '4' RegularExpressionNonTerminator
74187 *
74188 * and the escape itself is then parsed by the regexp engine.
74189 * This is the current implementation.
74190 *
74191 * Minor spec inconsistency:
74192 *
74193 * E5 Section 7.8.5 RegularExpressionBackslashSequence is:
74194 *
74195 * \ RegularExpressionNonTerminator
74196 *
74197 * while Section A.1 RegularExpressionBackslashSequence is:
74198 *
74199 * \ NonTerminator
74200 *
74201 * The latter is not normative and a typo.
74202 *
74203 */
74204
74205 /* first, parse regexp body roughly */
74206
74207 duk_small_int_t state = 0; /* 0=base, 1=esc, 2=class, 3=class+esc */
74208
74209 DUK__INITBUFFER(lex_ctx);
74210 for (;;) {
74211 DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */
74212 x = DUK__L0();
74213 if (x < 0 || duk_unicode_is_line_terminator(x)) {
74214 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in regexp");
74215 }
74216 x = DUK__L0(); /* re-read to avoid spill / fetch */
74217 if (state == 0) {
74218 if (x == '/') {
74219 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */
74220 break;
74221 } else if (x == '\\') {
74222 state = 1;
74223 } else if (x == '[') {
74224 state = 2;
74225 }
74226 } else if (state == 1) {
74227 state = 0;
74228 } else if (state == 2) {
74229 if (x == ']') {
74230 state = 0;
74231 } else if (x == '\\') {
74232 state = 3;
74233 }
74234 } else { /* state == 3 */
74235 state = 2;
74236 }
74237 DUK__APPENDBUFFER(lex_ctx, x);
74238 }
74239 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74240 out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74241
74242 /* second, parse flags */
74243
74244 DUK__INITBUFFER(lex_ctx);
74245 for (;;) {
74246 x = DUK__L0();
74247 if (!duk_unicode_is_identifier_part(x)) {
74248 break;
74249 }
74250 x = DUK__L0(); /* re-read to avoid spill / fetch */
74251 DUK__APPENDBUFFER(lex_ctx, x);
74252 DUK__ADVANCECHARS(lex_ctx, 1);
74253 }
74254 duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
74255 out_token->str2 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
74256
74257 DUK__INITBUFFER(lex_ctx); /* free some memory */
74258
74259 /* validation of the regexp is caller's responsibility */
74260
74261 advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
74262#else
74263 DUK_ERROR_SYNTAX(lex_ctx->thr, "regexp support disabled");
74264#endif
74265 } else if (DUK__L1() == '=') {
74266 /* "/=" and not in regexp mode */
74267 advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
74268 } else {
74269 /* "/" and not in regexp mode */
74270 advtok = DUK__ADVTOK(1, DUK_TOK_DIV);
74271 }
74272 break;
74273 case DUK_ASC_LCURLY: /* '{' */
74274 advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY);
74275 break;
74276 case DUK_ASC_RCURLY: /* '}' */
74277 advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY);
74278 break;
74279 case DUK_ASC_LPAREN: /* '(' */
74280 advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN);
74281 break;
74282 case DUK_ASC_RPAREN: /* ')' */
74283 advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN);
74284 break;
74285 case DUK_ASC_LBRACKET: /* '[' */
74286 advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET);
74287 break;
74288 case DUK_ASC_RBRACKET: /* ']' */
74289 advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET);
74290 break;
74291 case DUK_ASC_PERIOD: /* '.' */
74292 if (DUK__ISDIGIT(DUK__L1())) {
74293 /* Period followed by a digit can only start DecimalLiteral
74294 * (handled in slow path). We could jump straight into the
74295 * DecimalLiteral handling but should avoid goto to inside
74296 * a block.
74297 */
74298 goto slow_path;
74299 }
74300 advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD);
74301 break;
74302 case DUK_ASC_SEMICOLON: /* ';' */
74303 advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON);
74304 break;
74305 case DUK_ASC_COMMA: /* ',' */
74306 advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
74307 break;
74308 case DUK_ASC_LANGLE: /* '<' */
74309 if (DUK__L1() == '<' && DUK__L2() == '=') {
74310 advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
74311 } else if (DUK__L1() == '=') {
74312 advtok = DUK__ADVTOK(2, DUK_TOK_LE);
74313 } else if (DUK__L1() == '<') {
74314 advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
74315 } else {
74316 advtok = DUK__ADVTOK(1, DUK_TOK_LT);
74317 }
74318 break;
74319 case DUK_ASC_RANGLE: /* '>' */
74320 if (DUK__L1() == '>' && DUK__L2() == '>' && DUK__L3() == '=') {
74321 advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
74322 } else if (DUK__L1() == '>' && DUK__L2() == '>') {
74323 advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
74324 } else if (DUK__L1() == '>' && DUK__L2() == '=') {
74325 advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
74326 } else if (DUK__L1() == '=') {
74327 advtok = DUK__ADVTOK(2, DUK_TOK_GE);
74328 } else if (DUK__L1() == '>') {
74329 advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
74330 } else {
74331 advtok = DUK__ADVTOK(1, DUK_TOK_GT);
74332 }
74333 break;
74334 case DUK_ASC_EQUALS: /* '=' */
74335 if (DUK__L1() == '=' && DUK__L2() == '=') {
74336 advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
74337 } else if (DUK__L1() == '=') {
74338 advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
74339 } else {
74340 advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
74341 }
74342 break;
74343 case DUK_ASC_EXCLAMATION: /* '!' */
74344 if (DUK__L1() == '=' && DUK__L2() == '=') {
74345 advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
74346 } else if (DUK__L1() == '=') {
74347 advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
74348 } else {
74349 advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
74350 }
74351 break;
74352 case DUK_ASC_PLUS: /* '+' */
74353 if (DUK__L1() == '+') {
74354 advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
74355 } else if (DUK__L1() == '=') {
74356 advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
74357 } else {
74358 advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
74359 }
74360 break;
74361 case DUK_ASC_MINUS: /* '-' */
74362 if (DUK__L1() == '-') {
74363 advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
74364 } else if (DUK__L1() == '=') {
74365 advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
74366 } else {
74367 advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
74368 }
74369 break;
74370 case DUK_ASC_STAR: /* '*' */
74371 if (DUK__L1() == '=') {
74372 advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
74373 } else {
74374 advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
74375 }
74376 break;
74377 case DUK_ASC_PERCENT: /* '%' */
74378 if (DUK__L1() == '=') {
74379 advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
74380 } else {
74381 advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
74382 }
74383 break;
74384 case DUK_ASC_AMP: /* '&' */
74385 if (DUK__L1() == '&') {
74386 advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
74387 } else if (DUK__L1() == '=') {
74388 advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
74389 } else {
74390 advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
74391 }
74392 break;
74393 case DUK_ASC_PIPE: /* '|' */
74394 if (DUK__L1() == '|') {
74395 advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
74396 } else if (DUK__L1() == '=') {
74397 advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
74398 } else {
74399 advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
74400 }
74401 break;
74402 case DUK_ASC_CARET: /* '^' */
74403 if (DUK__L1() == '=') {
74404 advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
74405 } else {
74406 advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
74407 }
74408 break;
74409 case DUK_ASC_TILDE: /* '~' */
74410 advtok = DUK__ADVTOK(1, DUK_TOK_BNOT);
74411 break;
74412 case DUK_ASC_QUESTION: /* '?' */
74413 advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION);
74414 break;
74415 case DUK_ASC_COLON: /* ':' */
74416 advtok = DUK__ADVTOK(1, DUK_TOK_COLON);
74417 break;
74418 case DUK_ASC_DOUBLEQUOTE: /* '"' */
74419 case DUK_ASC_SINGLEQUOTE: { /* '\'' */
74420 duk_small_int_t quote = x; /* Note: duk_uint8_t type yields larger code */
74421 duk_small_int_t adv;
74422
74423 DUK__INITBUFFER(lex_ctx);
74424 for (;;) {
74425 DUK__ADVANCECHARS(lex_ctx, 1); /* eat opening quote on first loop */
74426 x = DUK__L0();
74427 if (x < 0 || duk_unicode_is_line_terminator(x)) {
74428 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
74429 }
74430 if (x == quote) {
74431 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */
74432 break;
74433 }
74434 if (x == '\\') {
74435 /* DUK__L0 -> '\' char
74436 * DUK__L1 ... DUK__L5 -> more lookup
74437 */
74438
74439 x = DUK__L1();
74440
74441 /* How much to advance before next loop; note that next loop
74442 * will advance by 1 anyway, so -1 from the total escape
74443 * length (e.g. len('\uXXXX') - 1 = 6 - 1). As a default,
74444 * 1 is good.
74445 */
74446 adv = 2 - 1; /* note: long live range */
74447
74448 if (x < 0) {
74449 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
74450 }
74451 if (duk_unicode_is_line_terminator(x)) {
74452 /* line continuation */
74453 if (x == 0x000d && DUK__L2() == 0x000a) {
74454 /* CR LF again a special case */
74455 adv = 3 - 1;
74456 }
74457 } else if (x == '\'') {
74458 DUK__APPENDBUFFER(lex_ctx, 0x0027);
74459 } else if (x == '"') {
74460 DUK__APPENDBUFFER(lex_ctx, 0x0022);
74461 } else if (x == '\\') {
74462 DUK__APPENDBUFFER(lex_ctx, 0x005c);
74463 } else if (x == 'b') {
74464 DUK__APPENDBUFFER(lex_ctx, 0x0008);
74465 } else if (x == 'f') {
74466 DUK__APPENDBUFFER(lex_ctx, 0x000c);
74467 } else if (x == 'n') {
74468 DUK__APPENDBUFFER(lex_ctx, 0x000a);
74469 } else if (x == 'r') {
74470 DUK__APPENDBUFFER(lex_ctx, 0x000d);
74471 } else if (x == 't') {
74472 DUK__APPENDBUFFER(lex_ctx, 0x0009);
74473 } else if (x == 'v') {
74474 DUK__APPENDBUFFER(lex_ctx, 0x000b);
74475 } else if (x == 'x') {
74476 adv = 4 - 1;
74477 DUK__APPENDBUFFER(lex_ctx, duk__decode_hexesc_from_window(lex_ctx, 2));
74478 } else if (x == 'u') {
74479 adv = 6 - 1;
74480 DUK__APPENDBUFFER(lex_ctx, duk__decode_uniesc_from_window(lex_ctx, 2));
74481 } else if (DUK__ISDIGIT(x)) {
74482 duk_codepoint_t ch = 0; /* initialized to avoid warnings of unused var */
74483
74484 /*
74485 * Octal escape or zero escape:
74486 * \0 (lookahead not DecimalDigit)
74487 * \1 ... \7 (lookahead not DecimalDigit)
74488 * \ZeroToThree OctalDigit (lookahead not DecimalDigit)
74489 * \FourToSeven OctalDigit (no lookahead restrictions)
74490 * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions)
74491 *
74492 * Zero escape is part of the standard syntax. Octal escapes are
74493 * defined in E5 Section B.1.2, and are only allowed in non-strict mode.
74494 * Any other productions starting with a decimal digit are invalid.
74495 */
74496
74497 if (x == '0' && !DUK__ISDIGIT(DUK__L2())) {
74498 /* Zero escape (also allowed in non-strict mode) */
74499 ch = 0;
74500 /* adv = 2 - 1 default OK */
74501#if defined(DUK_USE_OCTAL_SUPPORT)
74502 } else if (strict_mode) {
74503 /* No other escape beginning with a digit in strict mode */
74504 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
74505 } else if (DUK__ISDIGIT03(x) && DUK__ISOCTDIGIT(DUK__L2()) && DUK__ISOCTDIGIT(DUK__L3())) {
74506 /* Three digit octal escape, digits validated. */
74507 adv = 4 - 1;
74508 ch = (duk__hexval(lex_ctx, x) << 6) +
74509 (duk__hexval(lex_ctx, DUK__L2()) << 3) +
74510 duk__hexval(lex_ctx, DUK__L3());
74511 } else if (((DUK__ISDIGIT03(x) && !DUK__ISDIGIT(DUK__L3())) || DUK__ISDIGIT47(x)) &&
74512 DUK__ISOCTDIGIT(DUK__L2())) {
74513 /* Two digit octal escape, digits validated.
74514 *
74515 * The if-condition is a bit tricky. We could catch e.g.
74516 * '\039' in the three-digit escape and fail it there (by
74517 * validating the digits), but we want to avoid extra
74518 * additional validation code.
74519 */
74520 adv = 3 - 1;
74521 ch = (duk__hexval(lex_ctx, x) << 3) +
74522 duk__hexval(lex_ctx, DUK__L2());
74523 } else if (DUK__ISDIGIT(x) && !DUK__ISDIGIT(DUK__L2())) {
74524 /* One digit octal escape, digit validated. */
74525 /* adv = 2 default OK */
74526 ch = duk__hexval(lex_ctx, x);
74527#else
74528 /* fall through to error */
74529#endif
74530 } else {
74531 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
74532 }
74533
74534 DUK__APPENDBUFFER(lex_ctx, ch);
74535 } else {
74536 /* escaped NonEscapeCharacter */
74537 DUK__APPENDBUFFER(lex_ctx, x);
74538 }
74539 DUK__ADVANCECHARS(lex_ctx, adv);
74540
74541 /* Track number of escapes; count not really needed but directive
74542 * prologues need to detect whether there were any escapes or line
74543 * continuations or not.
74544 */
74545 out_token->num_escapes++;
74546 } else {
74547 /* part of string */
74548 DUK__APPENDBUFFER(lex_ctx, x);
74549 }
74550 }
74551
74552 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74553 out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74554
74555 DUK__INITBUFFER(lex_ctx); /* free some memory */
74556
74557 advtok = DUK__ADVTOK(0, DUK_TOK_STRING);
74558 break;
74559 }
74560 default:
74561 goto slow_path;
74562 } /* switch */
74563
74564 goto skip_slow_path;
74565
74566 slow_path:
74567 if (duk_unicode_is_line_terminator(x)) {
74568 if (x == 0x000d && DUK__L1() == 0x000a) {
74569 /*
74570 * E5 Section 7.3: CR LF is detected as a single line terminator for
74571 * line numbers. Here we also detect it as a single line terminator
74572 * token.
74573 */
74574 DUK__ADVANCECHARS(lex_ctx, 2);
74575 } else {
74576 DUK__ADVANCECHARS(lex_ctx, 1);
74577 }
74578 got_lineterm = 1;
74579 goto restart_lineupdate;
74580 } else if (duk_unicode_is_identifier_start(x) || x == '\\') {
74581 /*
74582 * Parse an identifier and then check whether it is:
74583 * - reserved word (keyword or other reserved word)
74584 * - "null" (NullLiteral)
74585 * - "true" (BooleanLiteral)
74586 * - "false" (BooleanLiteral)
74587 * - anything else => identifier
74588 *
74589 * This does not follow the E5 productions cleanly, but is
74590 * useful and compact.
74591 *
74592 * Note that identifiers may contain Unicode escapes,
74593 * see E5 Sections 6 and 7.6. They must be decoded first,
74594 * and the result checked against allowed characters.
74595 * The above if-clause accepts an identifier start and an
74596 * '\' character -- no other token can begin with a '\'.
74597 *
74598 * Note that "get" and "set" are not reserved words in E5
74599 * specification so they are recognized as plain identifiers
74600 * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not
74601 * used now). The compiler needs to work around this.
74602 *
74603 * Strictly speaking, following Ecmascript longest match
74604 * specification, an invalid escape for the first character
74605 * should cause a syntax error. However, an invalid escape
74606 * for IdentifierParts should just terminate the identifier
74607 * early (longest match), and let the next tokenization
74608 * fail. For instance Rhino croaks with 'foo\z' when
74609 * parsing the identifier. This has little practical impact.
74610 */
74611
74612 duk_small_int_t i, i_end;
74613 duk_bool_t first = 1;
74614 duk_hstring *str;
74615
74616 DUK__INITBUFFER(lex_ctx);
74617 for (;;) {
74618 /* re-lookup first char on first loop */
74619 if (DUK__L0() == '\\') {
74620 duk_codepoint_t ch;
74621 if (DUK__L1() != 'u') {
74622 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
74623 }
74624
74625 ch = duk__decode_uniesc_from_window(lex_ctx, 2);
74626
74627 /* IdentifierStart is stricter than IdentifierPart, so if the first
74628 * character is escaped, must have a stricter check here.
74629 */
74630 if (!(first ? duk_unicode_is_identifier_start(ch) : duk_unicode_is_identifier_part(ch))) {
74631 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
74632 }
74633 DUK__APPENDBUFFER(lex_ctx, ch);
74634 DUK__ADVANCECHARS(lex_ctx, 6);
74635
74636 /* Track number of escapes: necessary for proper keyword
74637 * detection.
74638 */
74639 out_token->num_escapes++;
74640 } else {
74641 /* Note: first character is checked against this. But because
74642 * IdentifierPart includes all IdentifierStart characters, and
74643 * the first character (if unescaped) has already been checked
74644 * in the if condition, this is OK.
74645 */
74646 if (!duk_unicode_is_identifier_part(DUK__L0())) {
74647 break;
74648 }
74649 DUK__APPENDBUFFER(lex_ctx, DUK__L0());
74650 DUK__ADVANCECHARS(lex_ctx, 1);
74651 }
74652 first = 0;
74653 }
74654
74655 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74656 out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74657 str = out_token->str1;
74658 DUK_ASSERT(str != NULL);
74659 out_token->t_nores = DUK_TOK_IDENTIFIER;
74660
74661 DUK__INITBUFFER(lex_ctx); /* free some memory */
74662
74663 /*
74664 * Interned identifier is compared against reserved words, which are
74665 * currently interned into the heap context. See genbuiltins.py.
74666 *
74667 * Note that an escape in the identifier disables recognition of
74668 * keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to
74669 * identifier named "if"). This is not necessarily compliant,
74670 * see test-dec-escaped-char-in-keyword.js.
74671 *
74672 * Note: "get" and "set" are awkward. They are not officially
74673 * ReservedWords (and indeed e.g. "var set = 1;" is valid), and
74674 * must come out as DUK_TOK_IDENTIFIER. The compiler needs to
74675 * work around this a bit.
74676 */
74677
74678 /* XXX: optimize by adding the token numbers directly into the
74679 * always interned duk_hstring objects (there should be enough
74680 * flag bits free for that)?
74681 */
74682
74683 i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED);
74684
74685 advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
74686 if (out_token->num_escapes == 0) {
74687 for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
74688 DUK_ASSERT(i >= 0 && i < DUK_HEAP_NUM_STRINGS);
74689 if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
74690 advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
74691 break;
74692 }
74693 }
74694 }
74695 } else if (DUK__ISDIGIT(x) || (x == '.')) {
74696 /* Note: decimal number may start with a period, but must be followed by a digit */
74697
74698 /*
74699 * DecimalLiteral, HexIntegerLiteral, OctalIntegerLiteral
74700 * "pre-parsing", followed by an actual, accurate parser step.
74701 *
74702 * Note: the leading sign character ('+' or '-') is -not- part of
74703 * the production in E5 grammar, and that the a DecimalLiteral
74704 * starting with a '0' must be followed by a non-digit. Leading
74705 * zeroes are syntax errors and must be checked for.
74706 *
74707 * XXX: the two step parsing process is quite awkward, it would
74708 * be more straightforward to allow numconv to parse the longest
74709 * valid prefix (it already does that, it only needs to indicate
74710 * where the input ended). However, the lexer decodes characters
74711 * using a lookup window, so this is not a trivial change.
74712 */
74713
74714 /* XXX: because of the final check below (that the literal is not
74715 * followed by a digit), this could maybe be simplified, if we bail
74716 * out early from a leading zero (and if there are no periods etc).
74717 * Maybe too complex.
74718 */
74719
74720 duk_double_t val;
74721 duk_bool_t int_only = 0;
74722 duk_bool_t allow_hex = 0;
74723 duk_small_int_t state; /* 0=before period/exp,
74724 * 1=after period, before exp
74725 * 2=after exp, allow '+' or '-'
74726 * 3=after exp and exp sign
74727 */
74728 duk_small_uint_t s2n_flags;
74729 duk_codepoint_t y;
74730
74731 DUK__INITBUFFER(lex_ctx);
74732 y = DUK__L1();
74733 if (x == '0' && (y == 'x' || y == 'X')) {
74734 DUK__APPENDBUFFER(lex_ctx, x);
74735 DUK__APPENDBUFFER(lex_ctx, y);
74736 DUK__ADVANCECHARS(lex_ctx, 2);
74737 int_only = 1;
74738 allow_hex = 1;
74739#if defined(DUK_USE_OCTAL_SUPPORT)
74740 } else if (!strict_mode && x == '0' && DUK__ISDIGIT(y)) {
74741 /* Note: if DecimalLiteral starts with a '0', it can only be
74742 * followed by a period or an exponent indicator which starts
74743 * with 'e' or 'E'. Hence the if-check above ensures that
74744 * OctalIntegerLiteral is the only valid NumericLiteral
74745 * alternative at this point (even if y is, say, '9').
74746 */
74747
74748 DUK__APPENDBUFFER(lex_ctx, x);
74749 DUK__ADVANCECHARS(lex_ctx, 1);
74750 int_only = 1;
74751#endif
74752 }
74753
74754 state = 0;
74755 for (;;) {
74756 x = DUK__L0(); /* re-lookup curr char on first round */
74757 if (DUK__ISDIGIT(x)) {
74758 /* Note: intentionally allow leading zeroes here, as the
74759 * actual parser will check for them.
74760 */
74761 if (state == 2) {
74762 state = 3;
74763 }
74764 } else if (allow_hex && DUK__ISHEXDIGIT(x)) {
74765 /* Note: 'e' and 'E' are also accepted here. */
74766 ;
74767 } else if (x == '.') {
74768 if (state >= 1 || int_only) {
74769 break;
74770 } else {
74771 state = 1;
74772 }
74773 } else if (x == 'e' || x == 'E') {
74774 if (state >= 2 || int_only) {
74775 break;
74776 } else {
74777 state = 2;
74778 }
74779 } else if (x == '-' || x == '+') {
74780 if (state != 2) {
74781 break;
74782 } else {
74783 state = 3;
74784 }
74785 } else {
74786 break;
74787 }
74788 DUK__APPENDBUFFER(lex_ctx, x);
74789 DUK__ADVANCECHARS(lex_ctx, 1);
74790 }
74791
74792 /* XXX: better coercion */
74793 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74794
74795 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
74796 DUK_S2N_FLAG_ALLOW_FRAC |
74797 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
74798 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
74799#if defined(DUK_USE_OCTAL_SUPPORT)
74800 (strict_mode ? 0 : DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) |
74801#endif
74802 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
74803
74804 duk_dup((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74805 duk_numconv_parse((duk_context *) lex_ctx->thr, 10 /*radix*/, s2n_flags);
74806 val = duk_to_number((duk_context *) lex_ctx->thr, -1);
74807 if (DUK_ISNAN(val)) {
74808 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
74809 }
74810 duk_replace((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
74811
74812 DUK__INITBUFFER(lex_ctx); /* free some memory */
74813
74814 /* Section 7.8.3 (note): NumericLiteral must be followed by something other than
74815 * IdentifierStart or DecimalDigit.
74816 */
74817
74818 if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
74819 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
74820 }
74821
74822 out_token->num = val;
74823 advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER);
74824 } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) {
74825 DUK__ADVANCECHARS(lex_ctx, 1);
74826 goto restart;
74827 } else if (x < 0) {
74828 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
74829 } else {
74830 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid token");
74831 }
74832 skip_slow_path:
74833
74834 /*
74835 * Shared exit path
74836 */
74837
74838 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
74839 out_token->t = advtok & 0xff;
74840 if (out_token->t_nores < 0) {
74841 out_token->t_nores = out_token->t;
74842 }
74843 out_token->lineterm = got_lineterm;
74844
74845 /* Automatic semicolon insertion is allowed if a token is preceded
74846 * by line terminator(s), or terminates a statement list (right curly
74847 * or EOF).
74848 */
74849 if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) {
74850 out_token->allow_auto_semi = 1;
74851 } else {
74852 out_token->allow_auto_semi = 0;
74853 }
74854}
74855
74856#if defined(DUK_USE_REGEXP_SUPPORT)
74857
74858/*
74859 * Parse a RegExp token. The grammar is described in E5 Section 15.10.
74860 * Terminal constructions (such as quantifiers) are parsed directly here.
74861 *
74862 * 0xffffffffU is used as a marker for "infinity" in quantifiers. Further,
74863 * DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that
74864 * will be accepted for a quantifier.
74865 */
74866
74867DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
74868 duk_small_int_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
74869 duk_codepoint_t x, y;
74870
74871 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
74872 DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
74873 return; /* unreachable */
74874 }
74875
74876 DUK_MEMZERO(out_token, sizeof(*out_token));
74877
74878 x = DUK__L0();
74879 y = DUK__L1();
74880
74881 DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y));
74882
74883 switch (x) {
74884 case '|': {
74885 advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
74886 break;
74887 }
74888 case '^': {
74889 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
74890 break;
74891 }
74892 case '$': {
74893 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
74894 break;
74895 }
74896 case '?': {
74897 out_token->qmin = 0;
74898 out_token->qmax = 1;
74899 if (y == '?') {
74900 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
74901 out_token->greedy = 0;
74902 } else {
74903 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
74904 out_token->greedy = 1;
74905 }
74906 break;
74907 }
74908 case '*': {
74909 out_token->qmin = 0;
74910 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
74911 if (y == '?') {
74912 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
74913 out_token->greedy = 0;
74914 } else {
74915 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
74916 out_token->greedy = 1;
74917 }
74918 break;
74919 }
74920 case '+': {
74921 out_token->qmin = 1;
74922 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
74923 if (y == '?') {
74924 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
74925 out_token->greedy = 0;
74926 } else {
74927 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
74928 out_token->greedy = 1;
74929 }
74930 break;
74931 }
74932 case '{': {
74933 /* Production allows 'DecimalDigits', including leading zeroes */
74934 duk_uint_fast32_t val1 = 0;
74935 duk_uint_fast32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
74936 duk_small_int_t digits = 0;
74937#if defined(DUK_USE_ES6_REGEXP_BRACES)
74938 duk_lexer_point lex_pt;
74939#endif
74940
74941#if defined(DUK_USE_ES6_REGEXP_BRACES)
74942 /* Store lexer position, restoring if quantifier is invalid. */
74943 DUK_LEXER_GETPOINT(lex_ctx, &lex_pt);
74944#endif
74945
74946 for (;;) {
74947 DUK__ADVANCECHARS(lex_ctx, 1); /* eat '{' on entry */
74948 x = DUK__L0();
74949 if (DUK__ISDIGIT(x)) {
74950 digits++;
74951 val1 = val1 * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
74952 } else if (x == ',') {
74953 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
74954 goto invalid_quantifier;
74955 }
74956 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
74957 goto invalid_quantifier;
74958 }
74959 if (DUK__L1() == '}') {
74960 /* form: { DecimalDigits , }, val1 = min count */
74961 if (digits == 0) {
74962 goto invalid_quantifier;
74963 }
74964 out_token->qmin = val1;
74965 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
74966 DUK__ADVANCECHARS(lex_ctx, 2);
74967 break;
74968 }
74969 val2 = val1;
74970 val1 = 0;
74971 digits = 0; /* not strictly necessary because of lookahead '}' above */
74972 } else if (x == '}') {
74973 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
74974 goto invalid_quantifier;
74975 }
74976 if (digits == 0) {
74977 goto invalid_quantifier;
74978 }
74979 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
74980 /* val2 = min count, val1 = max count */
74981 out_token->qmin = val2;
74982 out_token->qmax = val1;
74983 } else {
74984 /* val1 = count */
74985 out_token->qmin = val1;
74986 out_token->qmax = val1;
74987 }
74988 DUK__ADVANCECHARS(lex_ctx, 1);
74989 break;
74990 } else {
74991 goto invalid_quantifier;
74992 }
74993 }
74994 if (DUK__L0() == '?') {
74995 out_token->greedy = 0;
74996 DUK__ADVANCECHARS(lex_ctx, 1);
74997 } else {
74998 out_token->greedy = 1;
74999 }
75000 advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
75001 break;
75002 invalid_quantifier:
75003#if defined(DUK_USE_ES6_REGEXP_BRACES)
75004 /* Failed to match the quantifier, restore lexer and parse
75005 * opening brace as a literal.
75006 */
75007 DUK_LEXER_SETPOINT(lex_ctx, &lex_pt);
75008 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
75009 out_token->num = '{';
75010#else
75011 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp quantifier");
75012#endif
75013 break;
75014 }
75015 case '.': {
75016 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
75017 break;
75018 }
75019 case '\\': {
75020 /* The E5.1 specification does not seem to allow IdentifierPart characters
75021 * to be used as identity escapes. Unfortunately this includes '$', which
75022 * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
75023 * Many other implementations (including V8 and Rhino, for instance) do
75024 * accept '\$' as a valid identity escape, which is quite pragmatic.
75025 * See: test-regexp-identity-escape-dollar.js.
75026 */
75027
75028 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */
75029 if (y == 'b') {
75030 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
75031 } else if (y == 'B') {
75032 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
75033 } else if (y == 'f') {
75034 out_token->num = 0x000c;
75035 } else if (y == 'n') {
75036 out_token->num = 0x000a;
75037 } else if (y == 't') {
75038 out_token->num = 0x0009;
75039 } else if (y == 'r') {
75040 out_token->num = 0x000d;
75041 } else if (y == 'v') {
75042 out_token->num = 0x000b;
75043 } else if (y == 'c') {
75044 x = DUK__L2();
75045 if ((x >= 'a' && x <= 'z') ||
75046 (x >= 'A' && x <= 'Z')) {
75047 out_token->num = (x % 32);
75048 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
75049 } else {
75050 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
75051 }
75052 } else if (y == 'x') {
75053 out_token->num = duk__decode_hexesc_from_window(lex_ctx, 2);
75054 advtok = DUK__ADVTOK(4, DUK_RETOK_ATOM_CHAR);
75055 } else if (y == 'u') {
75056 out_token->num = duk__decode_uniesc_from_window(lex_ctx, 2);
75057 advtok = DUK__ADVTOK(6, DUK_RETOK_ATOM_CHAR);
75058 } else if (y == 'd') {
75059 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
75060 } else if (y == 'D') {
75061 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
75062 } else if (y == 's') {
75063 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
75064 } else if (y == 'S') {
75065 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
75066 } else if (y == 'w') {
75067 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
75068 } else if (y == 'W') {
75069 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
75070 } else if (DUK__ISDIGIT(y)) {
75071 /* E5 Section 15.10.2.11 */
75072 if (y == '0') {
75073 if (DUK__ISDIGIT(DUK__L2())) {
75074 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
75075 }
75076 out_token->num = 0x0000;
75077 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
75078 } else {
75079 /* XXX: shared parsing? */
75080 duk_uint_fast32_t val = 0;
75081 duk_small_int_t i;
75082 for (i = 0; ; i++) {
75083 if (i >= DUK__MAX_RE_DECESC_DIGITS) {
75084 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
75085 }
75086 DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */
75087 x = DUK__L0();
75088 if (!DUK__ISDIGIT(x)) {
75089 break;
75090 }
75091 val = val * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
75092 }
75093 /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
75094 advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
75095 out_token->num = val;
75096 }
75097 } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
75098#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
75099 y == '$' ||
75100#endif
75101 y == DUK_UNICODE_CP_ZWNJ ||
75102 y == DUK_UNICODE_CP_ZWJ) {
75103 /* IdentityEscape, with dollar added as a valid additional
75104 * non-standard escape (see test-regexp-identity-escape-dollar.js).
75105 * Careful not to match end-of-buffer (<0) here.
75106 */
75107 out_token->num = y;
75108 } else {
75109 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
75110 }
75111 break;
75112 }
75113 case '(': {
75114 /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
75115
75116 if (y == '?') {
75117 if (DUK__L2() == '=') {
75118 /* (?= */
75119 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
75120 } else if (DUK__L2() == '!') {
75121 /* (?! */
75122 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
75123 } else if (DUK__L2() == ':') {
75124 /* (?: */
75125 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
75126 } else {
75127 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp group");
75128 return;
75129 }
75130 } else {
75131 /* ( */
75132 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP);
75133 }
75134 break;
75135 }
75136 case ')': {
75137 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
75138 break;
75139 }
75140 case '[': {
75141 /*
75142 * To avoid creating a heavy intermediate value for the list of ranges,
75143 * only the start token ('[' or '[^') is parsed here. The regexp
75144 * compiler parses the ranges itself.
75145 */
75146 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
75147 if (y == '^') {
75148 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
75149 }
75150 break;
75151 }
75152#if !defined(DUK_USE_ES6_REGEXP_BRACES)
75153 case '}':
75154#endif
75155 case ']': {
75156 /* Although these could be parsed as PatternCharacters unambiguously (here),
75157 * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
75158 */
75159 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp character");
75160 break;
75161 }
75162 case -1: {
75163 /* EOF */
75164 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
75165 break;
75166 }
75167 default: {
75168 /* PatternCharacter, all excluded characters are matched by cases above */
75169 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
75170 out_token->num = x;
75171 break;
75172 }
75173 }
75174
75175 /*
75176 * Shared exit path
75177 */
75178
75179 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
75180 out_token->t = advtok & 0xff;
75181}
75182
75183/*
75184 * Special parser for character classes; calls callback for every
75185 * range parsed and returns the number of ranges present.
75186 */
75187
75188/* XXX: this duplicates functionality in duk_regexp.c where a similar loop is
75189 * required anyway. We could use that BUT we need to update the regexp compiler
75190 * 'nranges' too. Work this out a bit more cleanly to save space.
75191 */
75192
75193/* XXX: the handling of character range detection is a bit convoluted.
75194 * Try to simplify and make smaller.
75195 */
75196
75197/* XXX: logic for handling character ranges is now incorrect, it will accept
75198 * e.g. [\d-z] whereas it should croak from it? SMJS accepts this too, though.
75199 *
75200 * Needs a read through and a lot of additional tests.
75201 */
75202
75203DUK_LOCAL
75204void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx,
75205 duk_re_range_callback gen_range,
75206 void *userdata,
75207 const duk_uint16_t *ranges,
75208 duk_small_int_t num) {
75209 const duk_uint16_t *ranges_end;
75210
75211 DUK_UNREF(lex_ctx);
75212
75213 ranges_end = ranges + num;
75214 while (ranges < ranges_end) {
75215 /* mark range 'direct', bypass canonicalization (see Wiki) */
75216 gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1);
75217 ranges += 2;
75218 }
75219}
75220
75221DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) {
75222 duk_codepoint_t start = -1;
75223 duk_codepoint_t ch;
75224 duk_codepoint_t x;
75225 duk_bool_t dash = 0;
75226
75227 DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
75228
75229 for (;;) {
75230 x = DUK__L0();
75231 DUK__ADVANCECHARS(lex_ctx, 1);
75232
75233 ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */
75234 DUK_UNREF(ch);
75235
75236 if (x < 0) {
75237 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in character class");
75238 } else if (x == ']') {
75239 if (start >= 0) {
75240 gen_range(userdata, start, start, 0);
75241 }
75242 break;
75243 } else if (x == '-') {
75244 if (start >= 0 && !dash && DUK__L0() != ']') {
75245 /* '-' as a range indicator */
75246 dash = 1;
75247 continue;
75248 } else {
75249 /* '-' verbatim */
75250 ch = x;
75251 }
75252 } else if (x == '\\') {
75253 /*
75254 * The escapes are same as outside a character class, except that \b has a
75255 * different meaning, and \B and backreferences are prohibited (see E5
75256 * Section 15.10.2.19). However, it's difficult to share code because we
75257 * handle e.g. "\n" very differently: here we generate a single character
75258 * range for it.
75259 */
75260
75261 x = DUK__L0();
75262 DUK__ADVANCECHARS(lex_ctx, 1);
75263
75264 if (x == 'b') {
75265 /* Note: '\b' in char class is different than outside (assertion),
75266 * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
75267 * check below.
75268 */
75269 ch = 0x0008;
75270 } else if (x == 'f') {
75271 ch = 0x000c;
75272 } else if (x == 'n') {
75273 ch = 0x000a;
75274 } else if (x == 't') {
75275 ch = 0x0009;
75276 } else if (x == 'r') {
75277 ch = 0x000d;
75278 } else if (x == 'v') {
75279 ch = 0x000b;
75280 } else if (x == 'c') {
75281 x = DUK__L0();
75282 DUK__ADVANCECHARS(lex_ctx, 1);
75283 if ((x >= 'a' && x <= 'z') ||
75284 (x >= 'A' && x <= 'Z')) {
75285 ch = (x % 32);
75286 } else {
75287 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
75288 return; /* never reached, but avoids warnings of
75289 * potentially unused variables.
75290 */
75291 }
75292 } else if (x == 'x') {
75293 ch = duk__decode_hexesc_from_window(lex_ctx, 0);
75294 DUK__ADVANCECHARS(lex_ctx, 2);
75295 } else if (x == 'u') {
75296 ch = duk__decode_uniesc_from_window(lex_ctx, 0);
75297 DUK__ADVANCECHARS(lex_ctx, 4);
75298 } else if (x == 'd') {
75299 duk__emit_u16_direct_ranges(lex_ctx,
75300 gen_range,
75301 userdata,
75302 duk_unicode_re_ranges_digit,
75303 sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
75304 ch = -1;
75305 } else if (x == 'D') {
75306 duk__emit_u16_direct_ranges(lex_ctx,
75307 gen_range,
75308 userdata,
75309 duk_unicode_re_ranges_not_digit,
75310 sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
75311 ch = -1;
75312 } else if (x == 's') {
75313 duk__emit_u16_direct_ranges(lex_ctx,
75314 gen_range,
75315 userdata,
75316 duk_unicode_re_ranges_white,
75317 sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
75318 ch = -1;
75319 } else if (x == 'S') {
75320 duk__emit_u16_direct_ranges(lex_ctx,
75321 gen_range,
75322 userdata,
75323 duk_unicode_re_ranges_not_white,
75324 sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
75325 ch = -1;
75326 } else if (x == 'w') {
75327 duk__emit_u16_direct_ranges(lex_ctx,
75328 gen_range,
75329 userdata,
75330 duk_unicode_re_ranges_wordchar,
75331 sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
75332 ch = -1;
75333 } else if (x == 'W') {
75334 duk__emit_u16_direct_ranges(lex_ctx,
75335 gen_range,
75336 userdata,
75337 duk_unicode_re_ranges_not_wordchar,
75338 sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
75339 ch = -1;
75340 } else if (DUK__ISDIGIT(x)) {
75341 /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */
75342 if (x == '0' && !DUK__ISDIGIT(DUK__L0())) {
75343 ch = 0x0000;
75344 } else {
75345 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
75346 }
75347 } else if (!duk_unicode_is_identifier_part(x)
75348#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
75349 || x == '$'
75350#endif
75351 ) {
75352 /* IdentityEscape */
75353 ch = x;
75354 } else {
75355 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
75356 }
75357 } else {
75358 /* character represents itself */
75359 ch = x;
75360 }
75361
75362 /* ch is a literal character here or -1 if parsed entity was
75363 * an escape such as "\s".
75364 */
75365
75366 if (ch < 0) {
75367 /* multi-character sets not allowed as part of ranges, see
75368 * E5 Section 15.10.2.15, abstract operation CharacterRange.
75369 */
75370 if (start >= 0) {
75371 if (dash) {
75372 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
75373 } else {
75374 gen_range(userdata, start, start, 0);
75375 start = -1;
75376 /* dash is already 0 */
75377 }
75378 }
75379 } else {
75380 if (start >= 0) {
75381 if (dash) {
75382 if (start > ch) {
75383 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
75384 }
75385 gen_range(userdata, start, ch, 0);
75386 start = -1;
75387 dash = 0;
75388 } else {
75389 gen_range(userdata, start, start, 0);
75390 start = ch;
75391 /* dash is already 0 */
75392 }
75393 } else {
75394 start = ch;
75395 }
75396 }
75397 }
75398
75399 return;
75400}
75401
75402#endif /* DUK_USE_REGEXP_SUPPORT */
75403#line 1 "duk_numconv.c"
75404/*
75405 * Number-to-string and string-to-number conversions.
75406 *
75407 * Slow path number-to-string and string-to-number conversion is based on
75408 * a Dragon4 variant, with fast paths for small integers. Big integer
75409 * arithmetic is needed for guaranteeing that the conversion is correct
75410 * and uses a minimum number of digits. The big number arithmetic has a
75411 * fixed maximum size and does not require dynamic allocations.
75412 *
75413 * See: doc/number-conversion.rst.
75414 */
75415
75416/* include removed: duk_internal.h */
75417
75418#define DUK__IEEE_DOUBLE_EXP_BIAS 1023
75419#define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */
75420
75421#define DUK__DIGITCHAR(x) duk_lc_digits[(x)]
75422
75423/*
75424 * Tables generated with src/gennumdigits.py.
75425 *
75426 * duk__str2num_digits_for_radix indicates, for each radix, how many input
75427 * digits should be considered significant for string-to-number conversion.
75428 * The input is also padded to this many digits to give the Dragon4
75429 * conversion enough (apparent) precision to work with.
75430 *
75431 * duk__str2num_exp_limits indicates, for each radix, the radix-specific
75432 * minimum/maximum exponent values (for a Dragon4 integer mantissa)
75433 * below and above which the number is guaranteed to underflow to zero
75434 * or overflow to Infinity. This allows parsing to keep bigint values
75435 * bounded.
75436 */
75437
75438DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = {
75439 69, 44, 35, 30, 27, 25, 23, 22, 20, 20, /* 2 to 11 */
75440 20, 19, 19, 18, 18, 17, 17, 17, 16, 16, /* 12 to 21 */
75441 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, /* 22 to 31 */
75442 14, 14, 14, 14, 14 /* 31 to 36 */
75443};
75444
75445typedef struct {
75446 duk_int16_t upper;
75447 duk_int16_t lower;
75448} duk__exp_limits;
75449
75450DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = {
75451 { 957, -1147 }, { 605, -725 }, { 479, -575 }, { 414, -496 },
75452 { 372, -446 }, { 342, -411 }, { 321, -384 }, { 304, -364 },
75453 { 291, -346 }, { 279, -334 }, { 268, -323 }, { 260, -312 },
75454 { 252, -304 }, { 247, -296 }, { 240, -289 }, { 236, -283 },
75455 { 231, -278 }, { 227, -273 }, { 223, -267 }, { 220, -263 },
75456 { 216, -260 }, { 213, -256 }, { 210, -253 }, { 208, -249 },
75457 { 205, -246 }, { 203, -244 }, { 201, -241 }, { 198, -239 },
75458 { 196, -237 }, { 195, -234 }, { 193, -232 }, { 191, -230 },
75459 { 190, -228 }, { 188, -226 }, { 187, -225 },
75460};
75461
75462/*
75463 * Limited functionality bigint implementation.
75464 *
75465 * Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits,
75466 * with the caller responsible for ensuring this is never exceeded. No memory
75467 * allocation (except stack) is needed for bigint computation. Operations
75468 * have been tailored for number conversion needs.
75469 *
75470 * Argument order is "assignment order", i.e. target first, then arguments:
75471 * x <- y * z --> duk__bi_mul(x, y, z);
75472 */
75473
75474/* This upper value has been experimentally determined; debug build will check
75475 * bigint size with assertions.
75476 */
75477#define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */
75478
75479#ifdef DUK_USE_DDDPRINT
75480#define DUK__BI_PRINT(name,x) duk__bi_print((name),(x))
75481#else
75482#define DUK__BI_PRINT(name,x)
75483#endif
75484
75485/* Current size is about 152 bytes. */
75486typedef struct {
75487 duk_small_int_t n;
75488 duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */
75489} duk__bigint;
75490
75491#ifdef DUK_USE_DDDPRINT
75492DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
75493 /* Overestimate required size; debug code so not critical to be tight. */
75494 char buf[DUK__BI_MAX_PARTS * 9 + 64];
75495 char *p = buf;
75496 duk_small_int_t i;
75497
75498 /* No NUL term checks in this debug code. */
75499 p += DUK_SPRINTF(p, "%p n=%ld", (void *) x, (long) x->n);
75500 if (x->n == 0) {
75501 p += DUK_SPRINTF(p, " 0");
75502 }
75503 for (i = x->n - 1; i >= 0; i--) {
75504 p += DUK_SPRINTF(p, " %08lx", (unsigned long) x->v[i]);
75505 }
75506
75507 DUK_DDD(DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf));
75508}
75509#endif
75510
75511#ifdef DUK_USE_ASSERTIONS
75512DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
75513 return (duk_small_int_t)
75514 ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
75515 ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ );
75516}
75517#endif
75518
75519DUK_LOCAL void duk__bi_normalize(duk__bigint *x) {
75520 duk_small_int_t i;
75521
75522 for (i = x->n - 1; i >= 0; i--) {
75523 if (x->v[i] != 0) {
75524 break;
75525 }
75526 }
75527
75528 /* Note: if 'x' is zero, x->n becomes 0 here */
75529 x->n = i + 1;
75530 DUK_ASSERT(duk__bi_is_valid(x));
75531}
75532
75533/* x <- y */
75534DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
75535 duk_small_int_t n;
75536
75537 n = y->n;
75538 x->n = n;
75539 if (n == 0) {
75540 return;
75541 }
75542 DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
75543}
75544
75545DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
75546 if (v == 0U) {
75547 x->n = 0;
75548 } else {
75549 x->n = 1;
75550 x->v[0] = v;
75551 }
75552 DUK_ASSERT(duk__bi_is_valid(x));
75553}
75554
75555/* Return value: <0 <=> x < y
75556 * 0 <=> x == y
75557 * >0 <=> x > y
75558 */
75559DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
75560 duk_small_int_t i, nx, ny;
75561 duk_uint32_t tx, ty;
75562
75563 DUK_ASSERT(duk__bi_is_valid(x));
75564 DUK_ASSERT(duk__bi_is_valid(y));
75565
75566 nx = x->n;
75567 ny = y->n;
75568 if (nx > ny) {
75569 goto ret_gt;
75570 }
75571 if (nx < ny) {
75572 goto ret_lt;
75573 }
75574 for (i = nx - 1; i >= 0; i--) {
75575 tx = x->v[i];
75576 ty = y->v[i];
75577
75578 if (tx > ty) {
75579 goto ret_gt;
75580 }
75581 if (tx < ty) {
75582 goto ret_lt;
75583 }
75584 }
75585
75586 return 0;
75587
75588 ret_gt:
75589 return 1;
75590
75591 ret_lt:
75592 return -1;
75593}
75594
75595/* x <- y + z */
75596#ifdef DUK_USE_64BIT_OPS
75597DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75598 duk_uint64_t tmp;
75599 duk_small_int_t i, ny, nz;
75600
75601 DUK_ASSERT(duk__bi_is_valid(y));
75602 DUK_ASSERT(duk__bi_is_valid(z));
75603
75604 if (z->n > y->n) {
75605 duk__bigint *t;
75606 t = y; y = z; z = t;
75607 }
75608 DUK_ASSERT(y->n >= z->n);
75609
75610 ny = y->n; nz = z->n;
75611 tmp = 0U;
75612 for (i = 0; i < ny; i++) {
75613 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75614 tmp += y->v[i];
75615 if (i < nz) {
75616 tmp += z->v[i];
75617 }
75618 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
75619 tmp = tmp >> 32;
75620 }
75621 if (tmp != 0U) {
75622 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75623 x->v[i++] = (duk_uint32_t) tmp;
75624 }
75625 x->n = i;
75626 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
75627
75628 /* no need to normalize */
75629 DUK_ASSERT(duk__bi_is_valid(x));
75630}
75631#else /* DUK_USE_64BIT_OPS */
75632DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75633 duk_uint32_t carry, tmp1, tmp2;
75634 duk_small_int_t i, ny, nz;
75635
75636 DUK_ASSERT(duk__bi_is_valid(y));
75637 DUK_ASSERT(duk__bi_is_valid(z));
75638
75639 if (z->n > y->n) {
75640 duk__bigint *t;
75641 t = y; y = z; z = t;
75642 }
75643 DUK_ASSERT(y->n >= z->n);
75644
75645 ny = y->n; nz = z->n;
75646 carry = 0U;
75647 for (i = 0; i < ny; i++) {
75648 /* Carry is detected based on wrapping which relies on exact 32-bit
75649 * types.
75650 */
75651 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75652 tmp1 = y->v[i];
75653 tmp2 = tmp1;
75654 if (i < nz) {
75655 tmp2 += z->v[i];
75656 }
75657
75658 /* Careful with carry condition:
75659 * - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678)
75660 * - If carry added: 0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678)
75661 */
75662 if (carry) {
75663 tmp2++;
75664 carry = (tmp2 <= tmp1 ? 1U : 0U);
75665 } else {
75666 carry = (tmp2 < tmp1 ? 1U : 0U);
75667 }
75668
75669 x->v[i] = tmp2;
75670 }
75671 if (carry) {
75672 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75673 DUK_ASSERT(carry == 1U);
75674 x->v[i++] = carry;
75675 }
75676 x->n = i;
75677 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
75678
75679 /* no need to normalize */
75680 DUK_ASSERT(duk__bi_is_valid(x));
75681}
75682#endif /* DUK_USE_64BIT_OPS */
75683
75684/* x <- y + z */
75685DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
75686 duk__bigint tmp;
75687
75688 DUK_ASSERT(duk__bi_is_valid(y));
75689
75690 /* XXX: this could be optimized; there is only one call site now though */
75691 duk__bi_set_small(&tmp, z);
75692 duk__bi_add(x, y, &tmp);
75693
75694 DUK_ASSERT(duk__bi_is_valid(x));
75695}
75696
75697#if 0 /* unused */
75698/* x <- x + y, use t as temp */
75699DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
75700 duk__bi_add(t, x, y);
75701 duk__bi_copy(x, t);
75702}
75703#endif
75704
75705/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
75706#ifdef DUK_USE_64BIT_OPS
75707DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75708 duk_small_int_t i, ny, nz;
75709 duk_uint32_t ty, tz;
75710 duk_int64_t tmp;
75711
75712 DUK_ASSERT(duk__bi_is_valid(y));
75713 DUK_ASSERT(duk__bi_is_valid(z));
75714 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
75715 DUK_ASSERT(y->n >= z->n);
75716
75717 ny = y->n; nz = z->n;
75718 tmp = 0;
75719 for (i = 0; i < ny; i++) {
75720 ty = y->v[i];
75721 if (i < nz) {
75722 tz = z->v[i];
75723 } else {
75724 tz = 0;
75725 }
75726 tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
75727 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
75728 tmp = tmp >> 32; /* 0 or -1 */
75729 }
75730 DUK_ASSERT(tmp == 0);
75731
75732 x->n = i;
75733 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
75734 DUK_ASSERT(duk__bi_is_valid(x));
75735}
75736#else
75737DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75738 duk_small_int_t i, ny, nz;
75739 duk_uint32_t tmp1, tmp2, borrow;
75740
75741 DUK_ASSERT(duk__bi_is_valid(y));
75742 DUK_ASSERT(duk__bi_is_valid(z));
75743 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
75744 DUK_ASSERT(y->n >= z->n);
75745
75746 ny = y->n; nz = z->n;
75747 borrow = 0U;
75748 for (i = 0; i < ny; i++) {
75749 /* Borrow is detected based on wrapping which relies on exact 32-bit
75750 * types.
75751 */
75752 tmp1 = y->v[i];
75753 tmp2 = tmp1;
75754 if (i < nz) {
75755 tmp2 -= z->v[i];
75756 }
75757
75758 /* Careful with borrow condition:
75759 * - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678)
75760 * - If borrow subtracted: 0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678)
75761 */
75762 if (borrow) {
75763 tmp2--;
75764 borrow = (tmp2 >= tmp1 ? 1U : 0U);
75765 } else {
75766 borrow = (tmp2 > tmp1 ? 1U : 0U);
75767 }
75768
75769 x->v[i] = tmp2;
75770 }
75771 DUK_ASSERT(borrow == 0U);
75772
75773 x->n = i;
75774 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
75775 DUK_ASSERT(duk__bi_is_valid(x));
75776}
75777#endif
75778
75779#if 0 /* unused */
75780/* x <- y - z */
75781DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
75782 duk__bigint tmp;
75783
75784 DUK_ASSERT(duk__bi_is_valid(y));
75785
75786 /* XXX: this could be optimized */
75787 duk__bi_set_small(&tmp, z);
75788 duk__bi_sub(x, y, &tmp);
75789
75790 DUK_ASSERT(duk__bi_is_valid(x));
75791}
75792#endif
75793
75794/* x <- x - y, use t as temp */
75795DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
75796 duk__bi_sub(t, x, y);
75797 duk__bi_copy(x, t);
75798}
75799
75800/* x <- y * z */
75801DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75802 duk_small_int_t i, j, nx, nz;
75803
75804 DUK_ASSERT(duk__bi_is_valid(y));
75805 DUK_ASSERT(duk__bi_is_valid(z));
75806
75807 nx = y->n + z->n; /* max possible */
75808 DUK_ASSERT(nx <= DUK__BI_MAX_PARTS);
75809
75810 if (nx == 0) {
75811 /* Both inputs are zero; cases where only one is zero can go
75812 * through main algorithm.
75813 */
75814 x->n = 0;
75815 return;
75816 }
75817
75818 DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * nx));
75819 x->n = nx;
75820
75821 nz = z->n;
75822 for (i = 0; i < y->n; i++) {
75823#ifdef DUK_USE_64BIT_OPS
75824 duk_uint64_t tmp = 0U;
75825 for (j = 0; j < nz; j++) {
75826 tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
75827 x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL);
75828 tmp = tmp >> 32;
75829 }
75830 if (tmp > 0) {
75831 DUK_ASSERT(i + j < nx);
75832 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
75833 DUK_ASSERT(x->v[i+j] == 0U);
75834 x->v[i+j] = (duk_uint32_t) tmp;
75835 }
75836#else
75837 /*
75838 * Multiply + add + carry for 32-bit components using only 16x16->32
75839 * multiplies and carry detection based on unsigned overflow.
75840 *
75841 * 1st mult, 32-bit: (A*2^16 + B)
75842 * 2nd mult, 32-bit: (C*2^16 + D)
75843 * 3rd add, 32-bit: E
75844 * 4th add, 32-bit: F
75845 *
75846 * (AC*2^16 + B) * (C*2^16 + D) + E + F
75847 * = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F
75848 * = AC*2^32 + (AD + BC)*2^16 + (BD + E + F)
75849 * = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F)
75850 */
75851 duk_uint32_t a, b, c, d, e, f;
75852 duk_uint32_t r, s, t;
75853
75854 a = y->v[i]; b = a & 0xffffUL; a = a >> 16;
75855
75856 f = 0;
75857 for (j = 0; j < nz; j++) {
75858 c = z->v[j]; d = c & 0xffffUL; c = c >> 16;
75859 e = x->v[i+j];
75860
75861 /* build result as: (r << 32) + s: start with (BD + E + F) */
75862 r = 0;
75863 s = b * d;
75864
75865 /* add E */
75866 t = s + e;
75867 if (t < s) { r++; } /* carry */
75868 s = t;
75869
75870 /* add F */
75871 t = s + f;
75872 if (t < s) { r++; } /* carry */
75873 s = t;
75874
75875 /* add BC*2^16 */
75876 t = b * c;
75877 r += (t >> 16);
75878 t = s + ((t & 0xffffUL) << 16);
75879 if (t < s) { r++; } /* carry */
75880 s = t;
75881
75882 /* add AD*2^16 */
75883 t = a * d;
75884 r += (t >> 16);
75885 t = s + ((t & 0xffffUL) << 16);
75886 if (t < s) { r++; } /* carry */
75887 s = t;
75888
75889 /* add AC*2^32 */
75890 t = a * c;
75891 r += t;
75892
75893 DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx",
75894 (unsigned long) y->v[i], (unsigned long) z->v[j],
75895 (unsigned long) x->v[i+j], (unsigned long) r,
75896 (unsigned long) s));
75897
75898 x->v[i+j] = s;
75899 f = r;
75900 }
75901 if (f > 0U) {
75902 DUK_ASSERT(i + j < nx);
75903 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
75904 DUK_ASSERT(x->v[i+j] == 0U);
75905 x->v[i+j] = (duk_uint32_t) f;
75906 }
75907#endif /* DUK_USE_64BIT_OPS */
75908 }
75909
75910 duk__bi_normalize(x);
75911 DUK_ASSERT(duk__bi_is_valid(x));
75912}
75913
75914/* x <- y * z */
75915DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
75916 duk__bigint tmp;
75917
75918 DUK_ASSERT(duk__bi_is_valid(y));
75919
75920 /* XXX: this could be optimized */
75921 duk__bi_set_small(&tmp, z);
75922 duk__bi_mul(x, y, &tmp);
75923
75924 DUK_ASSERT(duk__bi_is_valid(x));
75925}
75926
75927/* x <- x * y, use t as temp */
75928DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
75929 duk__bi_mul(t, x, y);
75930 duk__bi_copy(x, t);
75931}
75932
75933/* x <- x * y, use t as temp */
75934DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) {
75935 duk__bi_mul_small(t, x, y);
75936 duk__bi_copy(x, t);
75937}
75938
75939DUK_LOCAL int duk__bi_is_even(duk__bigint *x) {
75940 DUK_ASSERT(duk__bi_is_valid(x));
75941 return (x->n == 0) || ((x->v[0] & 0x01) == 0);
75942}
75943
75944DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) {
75945 DUK_ASSERT(duk__bi_is_valid(x));
75946 return (x->n == 0); /* this is the case for normalized numbers */
75947}
75948
75949/* Bigint is 2^52. Used to detect normalized IEEE double mantissa values
75950 * which are at the lowest edge (next floating point value downwards has
75951 * a different exponent). The lowest mantissa has the form:
75952 *
75953 * 1000........000 (52 zeroes; only "hidden bit" is set)
75954 */
75955DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) {
75956 DUK_ASSERT(duk__bi_is_valid(x));
75957 return (duk_small_int_t)
75958 (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32)));
75959}
75960
75961/* x <- (1<<y) */
75962DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
75963 duk_small_int_t n, r;
75964
75965 n = (y / 32) + 1;
75966 DUK_ASSERT(n > 0);
75967 r = y % 32;
75968 DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * n);
75969 x->n = n;
75970 x->v[n - 1] = (((duk_uint32_t) 1) << r);
75971}
75972
75973/* x <- b^y; use t1 and t2 as temps */
75974DUK_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) {
75975 /* Fast path the binary case */
75976
75977 DUK_ASSERT(x != t1 && x != t2 && t1 != t2); /* distinct bignums, easy mistake to make */
75978 DUK_ASSERT(b >= 0);
75979 DUK_ASSERT(y >= 0);
75980
75981 if (b == 2) {
75982 duk__bi_twoexp(x, y);
75983 return;
75984 }
75985
75986 /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */
75987
75988 DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
75989
75990 duk__bi_set_small(x, 1);
75991 duk__bi_set_small(t1, b);
75992 for (;;) {
75993 /* Loop structure ensures that we don't compute t1^2 unnecessarily
75994 * on the final round, as that might create a bignum exceeding the
75995 * current DUK__BI_MAX_PARTS limit.
75996 */
75997 if (y & 0x01) {
75998 duk__bi_mul_copy(x, t1, t2);
75999 }
76000 y = y >> 1;
76001 if (y == 0) {
76002 break;
76003 }
76004 duk__bi_mul_copy(t1, t1, t2);
76005 }
76006
76007 DUK__BI_PRINT("exp_small result", x);
76008}
76009
76010/*
76011 * A Dragon4 number-to-string variant, based on:
76012 *
76013 * Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers
76014 * Accurately"
76015 *
76016 * Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers
76017 * Quickly and Accurately"
76018 *
76019 * The current algorithm is based on Figure 1 of the Burger-Dybvig paper,
76020 * i.e. the base implementation without logarithm estimation speedups
76021 * (these would increase code footprint considerably). Fixed-format output
76022 * does not follow the suggestions in the paper; instead, we generate an
76023 * extra digit and round-with-carry.
76024 *
76025 * The same algorithm is used for number parsing (with b=10 and B=2)
76026 * by generating one extra digit and doing rounding manually.
76027 *
76028 * See doc/number-conversion.rst for limitations.
76029 */
76030
76031/* Maximum number of digits generated. */
76032#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + spare */
76033
76034/* Maximum number of characters in formatted value. */
76035#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + spare */
76036
76037/* Number and (minimum) size of bigints in the nc_ctx structure. */
76038#define DUK__NUMCONV_CTX_NUM_BIGINTS 7
76039#define DUK__NUMCONV_CTX_BIGINTS_SIZE (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS)
76040
76041typedef struct {
76042 /* Currently about 7*152 = 1064 bytes. The space for these
76043 * duk__bigints is used also as a temporary buffer for generating
76044 * the final string. This is a bit awkard; a union would be
76045 * more correct.
76046 */
76047 duk__bigint f, r, s, mp, mm, t1, t2;
76048
76049 duk_small_int_t is_s2n; /* if 1, doing a string-to-number; else doing a number-to-string */
76050 duk_small_int_t is_fixed; /* if 1, doing a fixed format output (not free format) */
76051 duk_small_int_t req_digits; /* requested number of output digits; 0 = free-format */
76052 duk_small_int_t abs_pos; /* digit position is absolute, not relative */
76053 duk_small_int_t e; /* exponent for 'f' */
76054 duk_small_int_t b; /* input radix */
76055 duk_small_int_t B; /* output radix */
76056 duk_small_int_t k; /* see algorithm */
76057 duk_small_int_t low_ok; /* see algorithm */
76058 duk_small_int_t high_ok; /* see algorithm */
76059 duk_small_int_t unequal_gaps; /* m+ != m- (very rarely) */
76060
76061 /* Buffer used for generated digits, values are in the range [0,B-1]. */
76062 duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS];
76063 duk_small_int_t count; /* digit count */
76064} duk__numconv_stringify_ctx;
76065
76066/* Note: computes with 'idx' in assertions, so caller beware.
76067 * 'idx' is preincremented, i.e. '1' on first call, because it
76068 * is more convenient for the caller.
76069 */
76070#define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x) do { \
76071 DUK_ASSERT((preinc_idx) - 1 >= 0); \
76072 DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \
76073 ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \
76074 } while (0)
76075
76076DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) {
76077 duk_uint8_t *p;
76078 duk_size_t len;
76079 duk_small_int_t dig;
76080 duk_small_int_t t;
76081
76082 DUK_ASSERT(radix >= 2 && radix <= 36);
76083
76084 /* A 32-bit unsigned integer formats to at most 32 digits (the
76085 * worst case happens with radix == 2). Output the digits backwards,
76086 * and use a memmove() to get them in the right place.
76087 */
76088
76089 p = buf + 32;
76090 for (;;) {
76091 t = x / radix;
76092 dig = x - t * radix;
76093 x = t;
76094
76095 DUK_ASSERT(dig >= 0 && dig < 36);
76096 *(--p) = DUK__DIGITCHAR(dig);
76097
76098 if (x == 0) {
76099 break;
76100 }
76101 }
76102 len = (duk_size_t) ((buf + 32) - p);
76103
76104 DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len);
76105
76106 return len;
76107}
76108
76109DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
76110 duk_small_int_t lowest_mantissa;
76111
76112#if 1
76113 /* Assume IEEE round-to-even, so that shorter encoding can be used
76114 * when round-to-even would produce correct result. By removing
76115 * this check (and having low_ok == high_ok == 0) the results would
76116 * still be accurate but in some cases longer than necessary.
76117 */
76118 if (duk__bi_is_even(&nc_ctx->f)) {
76119 DUK_DDD(DUK_DDDPRINT("f is even"));
76120 nc_ctx->low_ok = 1;
76121 nc_ctx->high_ok = 1;
76122 } else {
76123 DUK_DDD(DUK_DDDPRINT("f is odd"));
76124 nc_ctx->low_ok = 0;
76125 nc_ctx->high_ok = 0;
76126 }
76127#else
76128 /* Note: not honoring round-to-even should work but now generates incorrect
76129 * results. For instance, 1e23 serializes to "a000...", i.e. the first digit
76130 * equals the radix (10). Scaling stops one step too early in this case.
76131 * Don't know why this is the case, but since this code path is unused, it
76132 * doesn't matter.
76133 */
76134 nc_ctx->low_ok = 0;
76135 nc_ctx->high_ok = 0;
76136#endif
76137
76138 /* For string-to-number, pretend we never have the lowest mantissa as there
76139 * is no natural "precision" for inputs. Having lowest_mantissa == 0, we'll
76140 * fall into the base cases for both e >= 0 and e < 0.
76141 */
76142 if (nc_ctx->is_s2n) {
76143 lowest_mantissa = 0;
76144 } else {
76145 lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f);
76146 }
76147
76148 nc_ctx->unequal_gaps = 0;
76149 if (nc_ctx->e >= 0) {
76150 /* exponent non-negative (and thus not minimum exponent) */
76151
76152 if (lowest_mantissa) {
76153 /* (>= e 0) AND (= f (expt b (- p 1)))
76154 *
76155 * be <- (expt b e) == b^e
76156 * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1)
76157 * r <- (* f be1 2) == 2 * f * b^(e+1) [if b==2 -> f * b^(e+2)]
76158 * s <- (* b 2) [if b==2 -> 4]
76159 * m+ <- be1 == b^(e+1)
76160 * m- <- be == b^e
76161 * k <- 0
76162 * B <- B
76163 * low_ok <- round
76164 * high_ok <- round
76165 */
76166
76167 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
76168 "lowest mantissa value for this exponent -> "
76169 "unequal gaps"));
76170
76171 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
76172 duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, nc_ctx->b); /* mp <- b^(e+1) */
76173 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
76174 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
76175 duk__bi_set_small(&nc_ctx->s, nc_ctx->b * 2); /* s <- 2 * b */
76176 nc_ctx->unequal_gaps = 1;
76177 } else {
76178 /* (>= e 0) AND (not (= f (expt b (- p 1))))
76179 *
76180 * be <- (expt b e) == b^e
76181 * r <- (* f be 2) == 2 * f * b^e [if b==2 -> f * b^(e+1)]
76182 * s <- 2
76183 * m+ <- be == b^e
76184 * m- <- be == b^e
76185 * k <- 0
76186 * B <- B
76187 * low_ok <- round
76188 * high_ok <- round
76189 */
76190
76191 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
76192 "not lowest mantissa for this exponent -> "
76193 "equal gaps"));
76194
76195 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
76196 duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm); /* mp <- b^e */
76197 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
76198 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^e */
76199 duk__bi_set_small(&nc_ctx->s, 2); /* s <- 2 */
76200 }
76201 } else {
76202 /* When doing string-to-number, lowest_mantissa is always 0 so
76203 * the exponent check, while incorrect, won't matter.
76204 */
76205 if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ &&
76206 lowest_mantissa /* lowest mantissa for this exponent*/) {
76207 /* r <- (* f b 2) [if b==2 -> (* f 4)]
76208 * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2 [if b==2 -> b^(2-e)]
76209 * m+ <- b == 2
76210 * m- <- 1
76211 * k <- 0
76212 * B <- B
76213 * low_ok <- round
76214 * high_ok <- round
76215 */
76216
76217 DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and "
76218 "lowest mantissa for this exponent -> "
76219 "unequal gaps"));
76220
76221 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, nc_ctx->b * 2); /* r <- (2 * b) * f */
76222 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 */
76223 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */
76224 duk__bi_set_small(&nc_ctx->mp, 2);
76225 duk__bi_set_small(&nc_ctx->mm, 1);
76226 nc_ctx->unequal_gaps = 1;
76227 } else {
76228 /* r <- (* f 2)
76229 * s <- (* (expt b (- e)) 2) == b^(-e) * 2 [if b==2 -> b^(1-e)]
76230 * m+ <- 1
76231 * m- <- 1
76232 * k <- 0
76233 * B <- B
76234 * low_ok <- round
76235 * high_ok <- round
76236 */
76237
76238 DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not "
76239 "lowest mantissa for this exponent -> "
76240 "equal gaps"));
76241
76242 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2); /* r <- 2 * f */
76243 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 */
76244 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(-e) * 2 */
76245 duk__bi_set_small(&nc_ctx->mp, 1);
76246 duk__bi_set_small(&nc_ctx->mm, 1);
76247 }
76248 }
76249}
76250
76251DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
76252 duk_small_int_t k = 0;
76253
76254 /* This is essentially the 'scale' algorithm, with recursion removed.
76255 * Note that 'k' is either correct immediately, or will move in one
76256 * direction in the loop. There's no need to do the low/high checks
76257 * on every round (like the Scheme algorithm does).
76258 *
76259 * The scheme algorithm finds 'k' and updates 's' simultaneously,
76260 * while the logical algorithm finds 'k' with 's' having its initial
76261 * value, after which 's' is updated separately (see the Burger-Dybvig
76262 * paper, Section 3.1, steps 2 and 3).
76263 *
76264 * The case where m+ == m- (almost always) is optimized for, because
76265 * it reduces the bigint operations considerably and almost always
76266 * applies. The scale loop only needs to work with m+, so this works.
76267 */
76268
76269 /* XXX: this algorithm could be optimized quite a lot by using e.g.
76270 * a logarithm based estimator for 'k' and performing B^n multiplication
76271 * using a lookup table or using some bit-representation based exp
76272 * algorithm. Currently we just loop, with significant performance
76273 * impact for very large and very small numbers.
76274 */
76275
76276 DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld",
76277 (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
76278 DUK__BI_PRINT("r(init)", &nc_ctx->r);
76279 DUK__BI_PRINT("s(init)", &nc_ctx->s);
76280 DUK__BI_PRINT("mp(init)", &nc_ctx->mp);
76281 DUK__BI_PRINT("mm(init)", &nc_ctx->mm);
76282
76283 for (;;) {
76284 DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld", (long) k));
76285 DUK__BI_PRINT("r", &nc_ctx->r);
76286 DUK__BI_PRINT("s", &nc_ctx->s);
76287 DUK__BI_PRINT("m+", &nc_ctx->mp);
76288 DUK__BI_PRINT("m-", &nc_ctx->mm);
76289
76290 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
76291 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) {
76292 DUK_DDD(DUK_DDDPRINT("k is too low"));
76293 /* r <- r
76294 * s <- (* s B)
76295 * m+ <- m+
76296 * m- <- m-
76297 * k <- (+ k 1)
76298 */
76299
76300 duk__bi_mul_small_copy(&nc_ctx->s, nc_ctx->B, &nc_ctx->t1);
76301 k++;
76302 } else {
76303 break;
76304 }
76305 }
76306
76307 /* k > 0 -> k was too low, and cannot be too high */
76308 if (k > 0) {
76309 goto skip_dec_k;
76310 }
76311
76312 for (;;) {
76313 DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld", (long) k));
76314 DUK__BI_PRINT("r", &nc_ctx->r);
76315 DUK__BI_PRINT("s", &nc_ctx->s);
76316 DUK__BI_PRINT("m+", &nc_ctx->mp);
76317 DUK__BI_PRINT("m-", &nc_ctx->mm);
76318
76319 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
76320 duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, nc_ctx->B); /* t2 = (* (+ r m+) B) */
76321 if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
76322 DUK_DDD(DUK_DDDPRINT("k is too high"));
76323 /* r <- (* r B)
76324 * s <- s
76325 * m+ <- (* m+ B)
76326 * m- <- (* m- B)
76327 * k <- (- k 1)
76328 */
76329 duk__bi_mul_small_copy(&nc_ctx->r, nc_ctx->B, &nc_ctx->t1);
76330 duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t1);
76331 if (nc_ctx->unequal_gaps) {
76332 DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
76333 duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t1);
76334 }
76335 k--;
76336 } else {
76337 break;
76338 }
76339 }
76340
76341 skip_dec_k:
76342
76343 if (!nc_ctx->unequal_gaps) {
76344 DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+"));
76345 duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp); /* mm <- mp */
76346 }
76347 nc_ctx->k = k;
76348
76349 DUK_DDD(DUK_DDDPRINT("final k: %ld", (long) k));
76350 DUK__BI_PRINT("r(final)", &nc_ctx->r);
76351 DUK__BI_PRINT("s(final)", &nc_ctx->s);
76352 DUK__BI_PRINT("mp(final)", &nc_ctx->mp);
76353 DUK__BI_PRINT("mm(final)", &nc_ctx->mm);
76354}
76355
76356DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
76357 duk_small_int_t tc1, tc2; /* terminating conditions */
76358 duk_small_int_t d; /* current digit */
76359 duk_small_int_t count = 0; /* digit count */
76360
76361 /*
76362 * Digit generation loop.
76363 *
76364 * Different termination conditions:
76365 *
76366 * 1. Free format output. Terminate when shortest accurate
76367 * representation found.
76368 *
76369 * 2. Fixed format output, with specific number of digits.
76370 * Ignore termination conditions, terminate when digits
76371 * generated. Caller requests an extra digit and rounds.
76372 *
76373 * 3. Fixed format output, with a specific absolute cut-off
76374 * position (e.g. 10 digits after decimal point). Note
76375 * that we always generate at least one digit, even if
76376 * the digit is below the cut-off point already.
76377 */
76378
76379 for (;;) {
76380 DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld",
76381 (long) count, (long) nc_ctx->k, (long) nc_ctx->B,
76382 (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
76383 DUK__BI_PRINT("r", &nc_ctx->r);
76384 DUK__BI_PRINT("s", &nc_ctx->s);
76385 DUK__BI_PRINT("m+", &nc_ctx->mp);
76386 DUK__BI_PRINT("m-", &nc_ctx->mm);
76387
76388 /* (quotient-remainder (* r B) s) using a dummy subtraction loop */
76389 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, nc_ctx->B); /* t1 <- (* r B) */
76390 d = 0;
76391 for (;;) {
76392 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
76393 break;
76394 }
76395 duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2); /* t1 <- t1 - s */
76396 d++;
76397 }
76398 duk__bi_copy(&nc_ctx->r, &nc_ctx->t1); /* r <- (remainder (* r B) s) */
76399 /* d <- (quotient (* r B) s) (in range 0...B-1) */
76400 DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
76401 DUK__BI_PRINT("r(rem)", &nc_ctx->r);
76402
76403 duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
76404 duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
76405 DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
76406 DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
76407
76408 /* Terminating conditions. For fixed width output, we just ignore the
76409 * terminating conditions (and pretend that tc1 == tc2 == false). The
76410 * the current shortcut for fixed-format output is to generate a few
76411 * extra digits and use rounding (with carry) to finish the output.
76412 */
76413
76414 if (nc_ctx->is_fixed == 0) {
76415 /* free-form */
76416 tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1));
76417
76418 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 <- (+ r m+) */
76419 tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1));
76420
76421 DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld", (long) tc1, (long) tc2));
76422 } else {
76423 /* fixed-format */
76424 tc1 = 0;
76425 tc2 = 0;
76426 }
76427
76428 /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call
76429 * on purpose, which is taken into account by the macro.
76430 */
76431 count++;
76432
76433 if (tc1) {
76434 if (tc2) {
76435 /* tc1 = true, tc2 = true */
76436 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2);
76437 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { /* (< (* r 2) s) */
76438 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)",
76439 (long) d, (long) nc_ctx->k));
76440 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
76441 } else {
76442 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)",
76443 (long) (d + 1), (long) nc_ctx->k));
76444 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
76445 }
76446 break;
76447 } else {
76448 /* tc1 = true, tc2 = false */
76449 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)",
76450 (long) d, (long) nc_ctx->k));
76451 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
76452 break;
76453 }
76454 } else {
76455 if (tc2) {
76456 /* tc1 = false, tc2 = true */
76457 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)",
76458 (long) (d + 1), (long) nc_ctx->k));
76459 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
76460 break;
76461 } else {
76462 /* tc1 = false, tc2 = false */
76463 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)",
76464 (long) d, (long) nc_ctx->k));
76465 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
76466
76467 /* r <- r (updated above: r <- (remainder (* r B) s)
76468 * s <- s
76469 * m+ <- m+ (updated above: m+ <- (* m+ B)
76470 * m- <- m- (updated above: m- <- (* m- B)
76471 * B, low_ok, high_ok are fixed
76472 */
76473
76474 /* fall through and continue for-loop */
76475 }
76476 }
76477
76478 /* fixed-format termination conditions */
76479 if (nc_ctx->is_fixed) {
76480 if (nc_ctx->abs_pos) {
76481 int pos = nc_ctx->k - count + 1; /* count is already incremented, take into account */
76482 DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld",
76483 (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
76484 if (pos <= nc_ctx->req_digits) {
76485 DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop"));
76486 break;
76487 }
76488 } else {
76489 DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld",
76490 (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
76491 if (count >= nc_ctx->req_digits) {
76492 DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop"));
76493 break;
76494 }
76495 }
76496 }
76497 } /* for */
76498
76499 nc_ctx->count = count;
76500
76501 DUK_DDD(DUK_DDDPRINT("generate finished"));
76502
76503#ifdef DUK_USE_DDDPRINT
76504 {
76505 duk_uint8_t buf[2048];
76506 duk_small_int_t i, t;
76507 DUK_MEMZERO(buf, sizeof(buf));
76508 for (i = 0; i < nc_ctx->count; i++) {
76509 t = nc_ctx->digits[i];
76510 if (t < 0 || t > 36) {
76511 buf[i] = (duk_uint8_t) '?';
76512 } else {
76513 buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t);
76514 }
76515 }
76516 DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'",
76517 (long) nc_ctx->k, (const char *) buf));
76518 }
76519#endif
76520}
76521
76522/* Round up digits to a given position. If position is out-of-bounds,
76523 * does nothing. If carry propagates over the first digit, a '1' is
76524 * prepended to digits and 'k' will be updated. Return value indicates
76525 * whether carry propagated over the first digit.
76526 *
76527 * Note that nc_ctx->count is NOT updated based on the rounding position
76528 * (it is updated only if carry overflows over the first digit and an
76529 * extra digit is prepended).
76530 */
76531DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) {
76532 duk_small_int_t t;
76533 duk_uint8_t *p;
76534 duk_uint8_t roundup_limit;
76535 duk_small_int_t ret = 0;
76536
76537 /*
76538 * round_idx points to the digit which is considered for rounding; the
76539 * digit to its left is the final digit of the rounded value. If round_idx
76540 * is zero, rounding will be performed; the result will either be an empty
76541 * rounded value or if carry happens a '1' digit is generated.
76542 */
76543
76544 if (round_idx >= nc_ctx->count) {
76545 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding",
76546 (long) round_idx, (long) nc_ctx->count));
76547 return 0;
76548 } else if (round_idx < 0) {
76549 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding",
76550 (long) round_idx));
76551 return 0;
76552 }
76553
76554 /*
76555 * Round-up limit.
76556 *
76557 * For even values, divides evenly, e.g. 10 -> roundup_limit=5.
76558 *
76559 * For odd values, rounds up, e.g. 3 -> roundup_limit=2.
76560 * If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up.
76561 */
76562 roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2);
76563
76564 p = &nc_ctx->digits[round_idx];
76565 if (*p >= roundup_limit) {
76566 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required"));
76567 /* carry */
76568 for (;;) {
76569 *p = 0;
76570 if (p == &nc_ctx->digits[0]) {
76571 DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
76572 DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
76573 (const void *) (&nc_ctx->digits[0]),
76574 (size_t) (sizeof(char) * nc_ctx->count));
76575 nc_ctx->digits[0] = 1; /* don't increase 'count' */
76576 nc_ctx->k++; /* position of highest digit changed */
76577 nc_ctx->count++; /* number of digits changed */
76578 ret = 1;
76579 break;
76580 }
76581
76582 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p",
76583 (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits));
76584 p--;
76585 t = *p;
76586 DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
76587 if (++t < nc_ctx->B) {
76588 DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
76589 *p = (duk_uint8_t) t;
76590 break;
76591 }
76592
76593 DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit"));
76594 }
76595 }
76596
76597 return ret;
76598}
76599
76600#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */
76601
76602DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
76603 duk_context *ctx,
76604 duk_small_int_t radix,
76605 duk_small_int_t digits,
76606 duk_small_uint_t flags,
76607 duk_small_int_t neg) {
76608 duk_small_int_t k;
76609 duk_small_int_t pos, pos_end;
76610 duk_small_int_t expt;
76611 duk_small_int_t dig;
76612 duk_uint8_t *q;
76613 duk_uint8_t *buf;
76614
76615 /*
76616 * The string conversion here incorporates all the necessary Ecmascript
76617 * semantics without attempting to be generic. nc_ctx->digits contains
76618 * nc_ctx->count digits (>= 1), with the topmost digit's 'position'
76619 * indicated by nc_ctx->k as follows:
76620 *
76621 * digits="123" count=3 k=0 --> 0.123
76622 * digits="123" count=3 k=1 --> 1.23
76623 * digits="123" count=3 k=5 --> 12300
76624 * digits="123" count=3 k=-1 --> 0.0123
76625 *
76626 * Note that the identifier names used for format selection are different
76627 * in Burger-Dybvig paper and Ecmascript specification (quite confusingly
76628 * so, because e.g. 'k' has a totally different meaning in each). See
76629 * documentation for discussion.
76630 *
76631 * Ecmascript doesn't specify any specific behavior for format selection
76632 * (e.g. when to use exponent notation) for non-base-10 numbers.
76633 *
76634 * The bigint space in the context is reused for string output, as there
76635 * is more than enough space for that (>1kB at the moment), and we avoid
76636 * allocating even more stack.
76637 */
76638
76639 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH);
76640 DUK_ASSERT(nc_ctx->count >= 1);
76641
76642 k = nc_ctx->k;
76643 buf = (duk_uint8_t *) &nc_ctx->f; /* XXX: union would be more correct */
76644 q = buf;
76645
76646 /* Exponent handling: if exponent format is used, record exponent value and
76647 * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23").
76648 *
76649 * toFixed() prevents exponent use; otherwise apply a set of criteria to
76650 * match the other API calls (toString(), toPrecision, etc).
76651 */
76652
76653 expt = DUK__NO_EXP;
76654 if (!nc_ctx->abs_pos /* toFixed() */) {
76655 if ((flags & DUK_N2S_FLAG_FORCE_EXP) || /* exponential notation forced */
76656 ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) && /* fixed precision and zero padding would be required */
76657 (k - digits >= 1)) || /* (e.g. k=3, digits=2 -> "12X") */
76658 ((k > 21 || k <= -6) && (radix == 10))) { /* toString() conditions */
76659 DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld",
76660 (long) k, (long) (k - 1)));
76661 expt = k - 1; /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */
76662 k = 1; /* generate mantissa with a single leading whole number digit */
76663 }
76664 }
76665
76666 if (neg) {
76667 *q++ = '-';
76668 }
76669
76670 /* Start position (inclusive) and end position (exclusive) */
76671 pos = (k >= 1 ? k : 1);
76672 if (nc_ctx->is_fixed) {
76673 if (nc_ctx->abs_pos) {
76674 /* toFixed() */
76675 pos_end = -digits;
76676 } else {
76677 pos_end = k - digits;
76678 }
76679 } else {
76680 pos_end = k - nc_ctx->count;
76681 }
76682 if (pos_end > 0) {
76683 pos_end = 0;
76684 }
76685
76686 DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, "
76687 "digits=%ld, abs_pos=%ld",
76688 (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end,
76689 (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos));
76690
76691 /* Digit generation */
76692 while (pos > pos_end) {
76693 DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld",
76694 (long) pos, (long) pos_end));
76695 if (pos == 0) {
76696 *q++ = (duk_uint8_t) '.';
76697 }
76698 if (pos > k) {
76699 *q++ = (duk_uint8_t) '0';
76700 } else if (pos <= k - nc_ctx->count) {
76701 *q++ = (duk_uint8_t) '0';
76702 } else {
76703 dig = nc_ctx->digits[k - pos];
76704 DUK_ASSERT(dig >= 0 && dig < nc_ctx->B);
76705 *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig);
76706 }
76707
76708 pos--;
76709 }
76710 DUK_ASSERT(pos <= 1);
76711
76712 /* Exponent */
76713 if (expt != DUK__NO_EXP) {
76714 /*
76715 * Exponent notation for non-base-10 numbers isn't specified in Ecmascript
76716 * specification, as it never explicitly turns up: non-decimal numbers can
76717 * only be formatted with Number.prototype.toString([radix]) and for that,
76718 * behavior is not explicitly specified.
76719 *
76720 * Logical choices include formatting the exponent as decimal (e.g. binary
76721 * 100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101).
76722 * The Dragon4 algorithm (in the original paper) prints the exponent value
76723 * in the target radix B. However, for radix values 15 and above, the
76724 * exponent separator 'e' is no longer easily parseable. Consider, for
76725 * instance, the number "1.faecee+1c".
76726 */
76727
76728 duk_size_t len;
76729 char expt_sign;
76730
76731 *q++ = 'e';
76732 if (expt >= 0) {
76733 expt_sign = '+';
76734 } else {
76735 expt_sign = '-';
76736 expt = -expt;
76737 }
76738 *q++ = (duk_uint8_t) expt_sign;
76739 len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix);
76740 q += len;
76741 }
76742
76743 duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
76744}
76745
76746/*
76747 * Conversion helpers
76748 */
76749
76750DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) {
76751 duk_double_union u;
76752 duk_uint32_t tmp;
76753 duk_small_int_t expt;
76754
76755 /*
76756 * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
76757 * A B C D E F G H
76758 *
76759 * s sign bit
76760 * eee... exponent field
76761 * fff... fraction
76762 *
76763 * ieee value = 1.ffff... * 2^(e - 1023) (normal)
76764 * = 0.ffff... * 2^(-1022) (denormal)
76765 *
76766 * algorithm v = f * b^e
76767 */
76768
76769 DUK_DBLUNION_SET_DOUBLE(&u, x);
76770
76771 nc_ctx->f.n = 2;
76772
76773 tmp = DUK_DBLUNION_GET_LOW32(&u);
76774 nc_ctx->f.v[0] = tmp;
76775 tmp = DUK_DBLUNION_GET_HIGH32(&u);
76776 nc_ctx->f.v[1] = tmp & 0x000fffffUL;
76777 expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL);
76778
76779 if (expt == 0) {
76780 /* denormal */
76781 expt = DUK__IEEE_DOUBLE_EXP_MIN - 52;
76782 duk__bi_normalize(&nc_ctx->f);
76783 } else {
76784 /* normal: implicit leading 1-bit */
76785 nc_ctx->f.v[1] |= 0x00100000UL;
76786 expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52;
76787 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); /* true, because v[1] has at least one bit set */
76788 }
76789
76790 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));
76791
76792 nc_ctx->e = expt;
76793}
76794
76795DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) {
76796 duk_double_union u;
76797 duk_small_int_t expt;
76798 duk_small_int_t i;
76799 duk_small_int_t bitstart;
76800 duk_small_int_t bitround;
76801 duk_small_int_t bitidx;
76802 duk_small_int_t skip_round;
76803 duk_uint32_t t, v;
76804
76805 DUK_ASSERT(nc_ctx->count == 53 + 1);
76806
76807 /* Sometimes this assert is not true right now; it will be true after
76808 * rounding. See: test-bug-numconv-mantissa-assert.js.
76809 */
76810 DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1); /* zero handled by caller */
76811
76812 /* Should not be required because the code below always sets both high
76813 * and low parts, but at least gcc-4.4.5 fails to deduce this correctly
76814 * (perhaps because the low part is set (seemingly) conditionally in a
76815 * loop), so this is here to avoid the bogus warning.
76816 */
76817 DUK_MEMZERO((void *) &u, sizeof(u));
76818
76819 /*
76820 * Figure out how generated digits match up with the mantissa,
76821 * and then perform rounding. If mantissa overflows, need to
76822 * recompute the exponent (it is bumped and may overflow to
76823 * infinity).
76824 *
76825 * For normal numbers the leading '1' is hidden and ignored,
76826 * and the last bit is used for rounding:
76827 *
76828 * rounding pt
76829 * <--------52------->|
76830 * 1 x x x x ... x x x x|y ==> x x x x ... x x x x
76831 *
76832 * For denormals, the leading '1' is included in the number,
76833 * and the rounding point is different:
76834 *
76835 * rounding pt
76836 * <--52 or less--->|
76837 * 1 x x x x ... x x|x x y ==> 0 0 ... 1 x x ... x x
76838 *
76839 * The largest denormals will have a mantissa beginning with
76840 * a '1' (the explicit leading bit); smaller denormals will
76841 * have leading zero bits.
76842 *
76843 * If the exponent would become too high, the result becomes
76844 * Infinity. If the exponent is so small that the entire
76845 * mantissa becomes zero, the result becomes zero.
76846 *
76847 * Note: the Dragon4 'k' is off-by-one with respect to the IEEE
76848 * exponent. For instance, k==0 indicates that the leading '1'
76849 * digit is at the first binary fraction position (0.1xxx...);
76850 * the corresponding IEEE exponent would be -1.
76851 */
76852
76853 skip_round = 0;
76854
76855 recheck_exp:
76856
76857 expt = nc_ctx->k - 1; /* IEEE exp without bias */
76858 if (expt > 1023) {
76859 /* Infinity */
76860 bitstart = -255; /* needed for inf: causes mantissa to become zero,
76861 * and rounding to be skipped.
76862 */
76863 expt = 2047;
76864 } else if (expt >= -1022) {
76865 /* normal */
76866 bitstart = 1; /* skip leading digit */
76867 expt += DUK__IEEE_DOUBLE_EXP_BIAS;
76868 DUK_ASSERT(expt >= 1 && expt <= 2046);
76869 } else {
76870 /* denormal or zero */
76871 bitstart = 1023 + expt; /* expt==-1023 -> bitstart=0 (leading 1);
76872 * expt==-1024 -> bitstart=-1 (one left of leading 1), etc
76873 */
76874 expt = 0;
76875 }
76876 bitround = bitstart + 52;
76877
76878 DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld",
76879 (long) expt, (long) bitstart, (long) bitround));
76880
76881 if (!skip_round) {
76882 if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) {
76883 /* Corner case: see test-numconv-parse-mant-carry.js. We could
76884 * just bump the exponent and update bitstart, but it's more robust
76885 * to recompute (but avoid rounding twice).
76886 */
76887 DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent"));
76888 skip_round = 1;
76889 goto recheck_exp;
76890 }
76891 }
76892
76893 /*
76894 * Create mantissa
76895 */
76896
76897 t = 0;
76898 for (i = 0; i < 52; i++) {
76899 bitidx = bitstart + 52 - 1 - i;
76900 if (bitidx >= nc_ctx->count) {
76901 v = 0;
76902 } else if (bitidx < 0) {
76903 v = 0;
76904 } else {
76905 v = nc_ctx->digits[bitidx];
76906 }
76907 DUK_ASSERT(v == 0 || v == 1);
76908 t += v << (i % 32);
76909 if (i == 31) {
76910 /* low 32 bits is complete */
76911 DUK_DBLUNION_SET_LOW32(&u, t);
76912 t = 0;
76913 }
76914 }
76915 /* t has high mantissa */
76916
76917 DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx",
76918 (unsigned long) t,
76919 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
76920
76921 DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
76922 t += expt << 20;
76923#if 0 /* caller handles sign change */
76924 if (negative) {
76925 t |= 0x80000000U;
76926 }
76927#endif
76928 DUK_DBLUNION_SET_HIGH32(&u, t);
76929
76930 DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx",
76931 (unsigned long) DUK_DBLUNION_GET_HIGH32(&u),
76932 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
76933
76934 *x = DUK_DBLUNION_GET_DOUBLE(&u);
76935}
76936
76937/*
76938 * Exposed number-to-string API
76939 *
76940 * Input: [ number ]
76941 * Output: [ string ]
76942 */
76943
76944DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
76945 duk_double_t x;
76946 duk_small_int_t c;
76947 duk_small_int_t neg;
76948 duk_uint32_t uval;
76949 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
76950 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
76951
76952 x = (duk_double_t) duk_require_number(ctx, -1);
76953 duk_pop(ctx);
76954
76955 /*
76956 * Handle special cases (NaN, infinity, zero).
76957 */
76958
76959 c = (duk_small_int_t) DUK_FPCLASSIFY(x);
76960 if (DUK_SIGNBIT((double) x)) {
76961 x = -x;
76962 neg = 1;
76963 } else {
76964 neg = 0;
76965 }
76966
76967 /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
76968 DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
76969
76970 if (c == DUK_FP_NAN) {
76971 duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
76972 return;
76973 } else if (c == DUK_FP_INFINITE) {
76974 if (neg) {
76975 /* -Infinity */
76976 duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
76977 } else {
76978 /* Infinity */
76979 duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
76980 }
76981 return;
76982 } else if (c == DUK_FP_ZERO) {
76983 /* We can't shortcut zero here if it goes through special formatting
76984 * (such as forced exponential notation).
76985 */
76986 ;
76987 }
76988
76989 /*
76990 * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
76991 * specially, as they're very likely for embedded programs. This
76992 * is now done for all radix values. We must be careful not to use
76993 * the fast path when special formatting (e.g. forced exponential)
76994 * is in force.
76995 *
76996 * XXX: could save space by supporting radix 10 only and using
76997 * sprintf "%lu" for the fast path and for exponent formatting.
76998 */
76999
77000 uval = (unsigned int) x;
77001 if (((double) uval) == x && /* integer number in range */
77002 flags == 0) { /* no special formatting */
77003 /* use bigint area as a temp */
77004 duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
77005 duk_uint8_t *p = buf;
77006
77007 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */
77008 if (neg && uval != 0) {
77009 /* no negative sign for zero */
77010 *p++ = (duk_uint8_t) '-';
77011 }
77012 p += duk__dragon4_format_uint32(p, uval, radix);
77013 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
77014 return;
77015 }
77016
77017 /*
77018 * Dragon4 setup.
77019 *
77020 * Convert double from IEEE representation for conversion;
77021 * normal finite values have an implicit leading 1-bit. The
77022 * slow path algorithm doesn't handle zero, so zero is special
77023 * cased here but still creates a valid nc_ctx, and goes
77024 * through normal formatting in case special formatting has
77025 * been requested (e.g. forced exponential format: 0 -> "0e+0").
77026 */
77027
77028 /* Would be nice to bulk clear the allocation, but the context
77029 * is 1-2 kilobytes and nothing should rely on it being zeroed.
77030 */
77031#if 0
77032 DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */
77033#endif
77034
77035 nc_ctx->is_s2n = 0;
77036 nc_ctx->b = 2;
77037 nc_ctx->B = radix;
77038 nc_ctx->abs_pos = 0;
77039 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
77040 nc_ctx->is_fixed = 1;
77041 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
77042 /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
77043 * but add an extra digit for rounding.
77044 */
77045 nc_ctx->abs_pos = 1;
77046 nc_ctx->req_digits = (-digits + 1) - 1;
77047 } else {
77048 nc_ctx->req_digits = digits + 1;
77049 }
77050 } else {
77051 nc_ctx->is_fixed = 0;
77052 nc_ctx->req_digits = 0;
77053 }
77054
77055 if (c == DUK_FP_ZERO) {
77056 /* Zero special case: fake requested number of zero digits; ensure
77057 * no sign bit is printed. Relative and absolute fixed format
77058 * require separate handling.
77059 */
77060 duk_small_int_t count;
77061 if (nc_ctx->is_fixed) {
77062 if (nc_ctx->abs_pos) {
77063 count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */
77064 } else {
77065 count = digits + 1; /* + 1 for rounding */
77066 }
77067 } else {
77068 count = 1;
77069 }
77070 DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
77071 DUK_ASSERT(count >= 1);
77072 DUK_MEMZERO((void *) nc_ctx->digits, count);
77073 nc_ctx->count = count;
77074 nc_ctx->k = 1; /* 0.000... */
77075 neg = 0;
77076 goto zero_skip;
77077 }
77078
77079 duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */
77080 DUK__BI_PRINT("f", &nc_ctx->f);
77081 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
77082
77083 /*
77084 * Dragon4 slow path digit generation.
77085 */
77086
77087 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
77088
77089 DUK_DDD(DUK_DDDPRINT("after prepare:"));
77090 DUK__BI_PRINT("r", &nc_ctx->r);
77091 DUK__BI_PRINT("s", &nc_ctx->s);
77092 DUK__BI_PRINT("mp", &nc_ctx->mp);
77093 DUK__BI_PRINT("mm", &nc_ctx->mm);
77094
77095 duk__dragon4_scale(nc_ctx);
77096
77097 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
77098 DUK__BI_PRINT("r", &nc_ctx->r);
77099 DUK__BI_PRINT("s", &nc_ctx->s);
77100 DUK__BI_PRINT("mp", &nc_ctx->mp);
77101 DUK__BI_PRINT("mm", &nc_ctx->mm);
77102
77103 duk__dragon4_generate(nc_ctx);
77104
77105 /*
77106 * Convert and push final string.
77107 */
77108
77109 zero_skip:
77110
77111 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
77112 /* Perform fixed-format rounding. */
77113 duk_small_int_t roundpos;
77114 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
77115 /* 'roundpos' is relative to nc_ctx->k and increases to the right
77116 * (opposite of how 'k' changes).
77117 */
77118 roundpos = -digits; /* absolute position for digit considered for rounding */
77119 roundpos = nc_ctx->k - roundpos;
77120 } else {
77121 roundpos = digits;
77122 }
77123 DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld",
77124 (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos));
77125 (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos);
77126
77127 /* Note: 'count' is currently not adjusted by rounding (i.e. the
77128 * digits are not "chopped off". That shouldn't matter because
77129 * the digit position (absolute or relative) is passed on to the
77130 * convert-and-push function.
77131 */
77132 }
77133
77134 duk__dragon4_convert_and_push(nc_ctx, ctx, radix, digits, flags, neg);
77135}
77136
77137/*
77138 * Exposed string-to-number API
77139 *
77140 * Input: [ string ]
77141 * Output: [ number ]
77142 *
77143 * If number parsing fails, a NaN is pushed as the result. If number parsing
77144 * fails due to an internal error, an InternalError is thrown.
77145 */
77146
77147DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags) {
77148 duk_hthread *thr = (duk_hthread *) ctx;
77149 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
77150 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
77151 duk_double_t res;
77152 duk_hstring *h_str;
77153 duk_small_int_t expt;
77154 duk_small_int_t expt_neg;
77155 duk_small_int_t expt_adj;
77156 duk_small_int_t neg;
77157 duk_small_int_t dig;
77158 duk_small_int_t dig_whole;
77159 duk_small_int_t dig_lzero;
77160 duk_small_int_t dig_frac;
77161 duk_small_int_t dig_expt;
77162 duk_small_int_t dig_prec;
77163 const duk__exp_limits *explim;
77164 const duk_uint8_t *p;
77165 duk_small_int_t ch;
77166
77167 /* This seems to waste a lot of stack frame entries, but good compilers
77168 * will compute these as needed below. Some of these initial flags are
77169 * also modified in the code below, so they can't all be removed.
77170 */
77171 duk_small_int_t trim_white = (flags & DUK_S2N_FLAG_TRIM_WHITE);
77172 duk_small_int_t allow_expt = (flags & DUK_S2N_FLAG_ALLOW_EXP);
77173 duk_small_int_t allow_garbage = (flags & DUK_S2N_FLAG_ALLOW_GARBAGE);
77174 duk_small_int_t allow_plus = (flags & DUK_S2N_FLAG_ALLOW_PLUS);
77175 duk_small_int_t allow_minus = (flags & DUK_S2N_FLAG_ALLOW_MINUS);
77176 duk_small_int_t allow_infinity = (flags & DUK_S2N_FLAG_ALLOW_INF);
77177 duk_small_int_t allow_frac = (flags & DUK_S2N_FLAG_ALLOW_FRAC);
77178 duk_small_int_t allow_naked_frac = (flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC);
77179 duk_small_int_t allow_empty_frac = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC);
77180 duk_small_int_t allow_empty = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
77181 duk_small_int_t allow_leading_zero = (flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO);
77182 duk_small_int_t allow_auto_hex_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT);
77183 duk_small_int_t allow_auto_oct_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT);
77184
77185 DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
77186 (duk_tval *) duk_get_tval(ctx, -1),
77187 (long) radix, (unsigned long) flags));
77188
77189 DUK_ASSERT(radix >= 2 && radix <= 36);
77190 DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix));
77191
77192 /*
77193 * Preliminaries: trim, sign, Infinity check
77194 *
77195 * We rely on the interned string having a NUL terminator, which will
77196 * cause a parse failure wherever it is encountered. As a result, we
77197 * don't need separate pointer checks.
77198 *
77199 * There is no special parsing for 'NaN' in the specification although
77200 * 'Infinity' (with an optional sign) is allowed in some contexts.
77201 * Some contexts allow plus/minus sign, while others only allow the
77202 * minus sign (like JSON.parse()).
77203 *
77204 * Automatic hex number detection (leading '0x' or '0X') and octal
77205 * number detection (leading '0' followed by at least one octal digit)
77206 * is done here too.
77207 */
77208
77209 if (trim_white) {
77210 /* Leading / trailing whitespace is sometimes accepted and
77211 * sometimes not. After white space trimming, all valid input
77212 * characters are pure ASCII.
77213 */
77214 duk_trim(ctx, -1);
77215 }
77216 h_str = duk_require_hstring(ctx, -1);
77217 DUK_ASSERT(h_str != NULL);
77218 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
77219
77220 neg = 0;
77221 ch = *p;
77222 if (ch == (duk_small_int_t) '+') {
77223 if (!allow_plus) {
77224 DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
77225 goto parse_fail;
77226 }
77227 p++;
77228 } else if (ch == (duk_small_int_t) '-') {
77229 if (!allow_minus) {
77230 DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
77231 goto parse_fail;
77232 }
77233 p++;
77234 neg = 1;
77235 }
77236
77237 ch = *p;
77238 if (allow_infinity && ch == (duk_small_int_t) 'I') {
77239 /* Don't check for Infinity unless the context allows it.
77240 * 'Infinity' is a valid integer literal in e.g. base-36:
77241 *
77242 * parseInt('Infinity', 36)
77243 * 1461559270678
77244 */
77245
77246 const duk_uint8_t *q;
77247
77248 /* borrow literal Infinity from builtin string */
77249 q = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(DUK_HTHREAD_STRING_INFINITY(thr));
77250 if (DUK_STRNCMP((const char *) p, (const char *) q, 8) == 0) {
77251 if (!allow_garbage && (p[8] != (duk_uint8_t) 0)) {
77252 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
77253 goto parse_fail;
77254 } else {
77255 res = DUK_DOUBLE_INFINITY;
77256 goto negcheck_and_ret;
77257 }
77258 }
77259 }
77260 if (ch == (duk_small_int_t) '0') {
77261 duk_small_int_t detect_radix = 0;
77262 ch = p[1];
77263 if (allow_auto_hex_int && (ch == (duk_small_int_t) 'x' || ch == (duk_small_int_t) 'X')) {
77264 DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
77265 detect_radix = 16;
77266 allow_empty = 0; /* interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
77267 p += 2;
77268 } else if (allow_auto_oct_int && (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
77269 DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
77270 detect_radix = 8;
77271 allow_empty = 1; /* interpret e.g. '09' as '0', not NaN */
77272 p += 1;
77273 }
77274 if (detect_radix > 0) {
77275 radix = detect_radix;
77276 allow_expt = 0;
77277 allow_frac = 0;
77278 allow_naked_frac = 0;
77279 allow_empty_frac = 0;
77280 allow_leading_zero = 1; /* allow e.g. '0x0009' and '00077' */
77281 }
77282 }
77283
77284 /*
77285 * Scan number and setup for Dragon4.
77286 *
77287 * The fast path case is detected during setup: an integer which
77288 * can be converted without rounding, no net exponent. The fast
77289 * path could be implemented as a separate scan, but may not really
77290 * be worth it: the multiplications for building 'f' are not
77291 * expensive when 'f' is small.
77292 *
77293 * The significand ('f') must contain enough bits of (apparent)
77294 * accuracy, so that Dragon4 will generate enough binary output digits.
77295 * For decimal numbers, this means generating a 20-digit significand,
77296 * which should yield enough practical accuracy to parse IEEE doubles.
77297 * In fact, the Ecmascript specification explicitly allows an
77298 * implementation to treat digits beyond 20 as zeroes (and even
77299 * to round the 20th digit upwards). For non-decimal numbers, the
77300 * appropriate number of digits has been precomputed for comparable
77301 * accuracy.
77302 *
77303 * Digit counts:
77304 *
77305 * [ dig_lzero ]
77306 * |
77307 * .+-..---[ dig_prec ]----.
77308 * | || |
77309 * 0000123.456789012345678901234567890e+123456
77310 * | | | | | |
77311 * `--+--' `------[ dig_frac ]-------' `-+--'
77312 * | |
77313 * [ dig_whole ] [ dig_expt ]
77314 *
77315 * dig_frac and dig_expt are -1 if not present
77316 * dig_lzero is only computed for whole number part
77317 *
77318 * Parsing state
77319 *
77320 * Parsing whole part dig_frac < 0 AND dig_expt < 0
77321 * Parsing fraction part dig_frac >= 0 AND dig_expt < 0
77322 * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0)
77323 *
77324 * Note: in case we hit an implementation limit (like exponent range),
77325 * we should throw an error, NOT return NaN or Infinity. Even with
77326 * very large exponent (or significand) values the final result may be
77327 * finite, so NaN/Infinity would be incorrect.
77328 */
77329
77330 duk__bi_set_small(&nc_ctx->f, 0);
77331 dig_prec = 0;
77332 dig_lzero = 0;
77333 dig_whole = 0;
77334 dig_frac = -1;
77335 dig_expt = -1;
77336 expt = 0;
77337 expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */
77338 expt_neg = 0;
77339 for (;;) {
77340 ch = *p++;
77341
77342 DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
77343 "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
77344 (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
77345 (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
77346 (long) dig_expt, (long) dig_lzero, (long) dig_prec));
77347 DUK__BI_PRINT("f", &nc_ctx->f);
77348
77349 /* Most common cases first. */
77350 if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
77351 dig = (int) ch - '0' + 0;
77352 } else if (ch == (duk_small_int_t) '.') {
77353 /* A leading digit is not required in some cases, e.g. accept ".123".
77354 * In other cases (JSON.parse()) a leading digit is required. This
77355 * is checked for after the loop.
77356 */
77357 if (dig_frac >= 0 || dig_expt >= 0) {
77358 if (allow_garbage) {
77359 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
77360 break;
77361 } else {
77362 DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed"));
77363 goto parse_fail;
77364 }
77365 }
77366
77367 if (!allow_frac) {
77368 /* Some contexts don't allow fractions at all; this can't be a
77369 * post-check because the state ('f' and expt) would be incorrect.
77370 */
77371 if (allow_garbage) {
77372 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
77373 break;
77374 } else {
77375 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed"));
77376 }
77377 }
77378
77379 DUK_DDD(DUK_DDDPRINT("start fraction part"));
77380 dig_frac = 0;
77381 continue;
77382 } else if (ch == (duk_small_int_t) 0) {
77383 DUK_DDD(DUK_DDDPRINT("NUL termination"));
77384 break;
77385 } else if (allow_expt && dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
77386 /* Note: we don't parse back exponent notation for anything else
77387 * than radix 10, so this is not an ambiguous check (e.g. hex
77388 * exponent values may have 'e' either as a significand digit
77389 * or as an exponent separator).
77390 *
77391 * If the exponent separator occurs twice, 'e' will be interpreted
77392 * as a digit (= 14) and will be rejected as an invalid decimal
77393 * digit.
77394 */
77395
77396 DUK_DDD(DUK_DDDPRINT("start exponent part"));
77397
77398 /* Exponent without a sign or with a +/- sign is accepted
77399 * by all call sites (even JSON.parse()).
77400 */
77401 ch = *p;
77402 if (ch == (duk_small_int_t) '-') {
77403 expt_neg = 1;
77404 p++;
77405 } else if (ch == (duk_small_int_t) '+') {
77406 p++;
77407 }
77408 dig_expt = 0;
77409 continue;
77410 } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
77411 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
77412 } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
77413 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
77414 } else {
77415 dig = 255; /* triggers garbage digit check below */
77416 }
77417 DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
77418
77419 if (dig >= radix) {
77420 if (allow_garbage) {
77421 DUK_DDD(DUK_DDDPRINT("garbage termination"));
77422 break;
77423 } else {
77424 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit"));
77425 goto parse_fail;
77426 }
77427 }
77428
77429 if (dig_expt < 0) {
77430 /* whole or fraction digit */
77431
77432 if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
77433 /* significant from precision perspective */
77434
77435 duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
77436 if (f_zero && dig == 0) {
77437 /* Leading zero is not counted towards precision digits; not
77438 * in the integer part, nor in the fraction part.
77439 */
77440 if (dig_frac < 0) {
77441 dig_lzero++;
77442 }
77443 } else {
77444 /* XXX: join these ops (multiply-accumulate), but only if
77445 * code footprint decreases.
77446 */
77447 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
77448 duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
77449 dig_prec++;
77450 }
77451 } else {
77452 /* Ignore digits beyond a radix-specific limit, but note them
77453 * in expt_adj.
77454 */
77455 expt_adj++;
77456 }
77457
77458 if (dig_frac >= 0) {
77459 dig_frac++;
77460 expt_adj--;
77461 } else {
77462 dig_whole++;
77463 }
77464 } else {
77465 /* exponent digit */
77466
77467 expt = expt * radix + dig;
77468 if (expt > DUK_S2N_MAX_EXPONENT) {
77469 /* impose a reasonable exponent limit, so that exp
77470 * doesn't need to get tracked using a bigint.
77471 */
77472 DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large"));
77473 goto parse_explimit_error;
77474 }
77475 dig_expt++;
77476 }
77477 }
77478
77479 /* Leading zero. */
77480
77481 if (dig_lzero > 0 && dig_whole > 1) {
77482 if (!allow_leading_zero) {
77483 DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
77484 goto parse_fail;
77485 }
77486 }
77487
77488 /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
77489
77490 if (dig_whole == 0) {
77491 if (dig_frac == 0) {
77492 /* "." is not accepted in any format */
77493 DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits"));
77494 goto parse_fail;
77495 } else if (dig_frac > 0) {
77496 /* ".123" */
77497 if (!allow_naked_frac) {
77498 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
77499 "leading integer digit(s)"));
77500 goto parse_fail;
77501 }
77502 } else {
77503 /* empty ("") is allowed in some formats (e.g. Number(''), as zero */
77504 if (!allow_empty) {
77505 DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
77506 goto parse_fail;
77507 }
77508 }
77509 } else {
77510 if (dig_frac == 0) {
77511 /* "123." is allowed in some formats */
77512 if (!allow_empty_frac) {
77513 DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
77514 goto parse_fail;
77515 }
77516 } else if (dig_frac > 0) {
77517 /* "123.456" */
77518 ;
77519 } else {
77520 /* "123" */
77521 ;
77522 }
77523 }
77524
77525 /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is
77526 * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
77527 */
77528
77529 if (dig_expt == 0) {
77530 if (!allow_garbage) {
77531 DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
77532 goto parse_fail;
77533 }
77534 DUK_ASSERT(expt == 0);
77535 }
77536
77537 if (expt_neg) {
77538 expt = -expt;
77539 }
77540 DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld",
77541 (long) expt, (long) expt_adj, (long) (expt + expt_adj)));
77542 expt += expt_adj;
77543
77544 /* Fast path check. */
77545
77546 if (nc_ctx->f.n <= 1 && /* 32-bit value */
77547 expt == 0 /* no net exponent */) {
77548 /* Fast path is triggered for no exponent and also for balanced exponent
77549 * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect
77550 * zero sign.
77551 */
77552
77553 /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
77554 DUK_DDD(DUK_DDDPRINT("fast path number parse"));
77555 if (nc_ctx->f.n == 1) {
77556 res = (double) nc_ctx->f.v[0];
77557 } else {
77558 res = 0.0;
77559 }
77560 goto negcheck_and_ret;
77561 }
77562
77563 /* Significand ('f') padding. */
77564
77565 while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
77566 /* Pad significand with "virtual" zero digits so that Dragon4 will
77567 * have enough (apparent) precision to work with.
77568 */
77569 DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
77570 duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
77571 DUK__BI_PRINT("f", &nc_ctx->f);
77572 expt--;
77573 dig_prec++;
77574 }
77575
77576 DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt));
77577
77578 /* Detect zero special case. */
77579
77580 if (nc_ctx->f.n == 0) {
77581 /* This may happen even after the fast path check, if exponent is
77582 * not balanced (e.g. "0e1"). Remember to respect zero sign.
77583 */
77584 DUK_DDD(DUK_DDDPRINT("significand is zero"));
77585 res = 0.0;
77586 goto negcheck_and_ret;
77587 }
77588
77589
77590 /* Quick reject of too large or too small exponents. This check
77591 * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
77592 * so zero check must be above.
77593 */
77594
77595 explim = &duk__str2num_exp_limits[radix - 2];
77596 if (expt > explim->upper) {
77597 DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite"));
77598 res = (duk_double_t) DUK_DOUBLE_INFINITY;
77599 goto negcheck_and_ret;
77600 } else if (expt < explim->lower) {
77601 DUK_DDD(DUK_DDDPRINT("exponent too small -> zero"));
77602 res = (duk_double_t) 0.0;
77603 goto negcheck_and_ret;
77604 }
77605
77606 nc_ctx->is_s2n = 1;
77607 nc_ctx->e = expt;
77608 nc_ctx->b = radix;
77609 nc_ctx->B = 2;
77610 nc_ctx->is_fixed = 1;
77611 nc_ctx->abs_pos = 0;
77612 nc_ctx->req_digits = 53 + 1;
77613
77614 DUK__BI_PRINT("f", &nc_ctx->f);
77615 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
77616
77617 /*
77618 * Dragon4 slow path (binary) digit generation.
77619 * An extra digit is generated for rounding.
77620 */
77621
77622 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
77623
77624 DUK_DDD(DUK_DDDPRINT("after prepare:"));
77625 DUK__BI_PRINT("r", &nc_ctx->r);
77626 DUK__BI_PRINT("s", &nc_ctx->s);
77627 DUK__BI_PRINT("mp", &nc_ctx->mp);
77628 DUK__BI_PRINT("mm", &nc_ctx->mm);
77629
77630 duk__dragon4_scale(nc_ctx);
77631
77632 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
77633 DUK__BI_PRINT("r", &nc_ctx->r);
77634 DUK__BI_PRINT("s", &nc_ctx->s);
77635 DUK__BI_PRINT("mp", &nc_ctx->mp);
77636 DUK__BI_PRINT("mm", &nc_ctx->mm);
77637
77638 duk__dragon4_generate(nc_ctx);
77639
77640 DUK_ASSERT(nc_ctx->count == 53 + 1);
77641
77642 /*
77643 * Convert binary digits into an IEEE double. Need to handle
77644 * denormals and rounding correctly.
77645 */
77646
77647 duk__dragon4_ctx_to_double(nc_ctx, &res);
77648 goto negcheck_and_ret;
77649
77650 negcheck_and_ret:
77651 if (neg) {
77652 res = -res;
77653 }
77654 duk_pop(ctx);
77655 duk_push_number(ctx, (double) res);
77656 DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
77657 return;
77658
77659 parse_fail:
77660 DUK_DDD(DUK_DDDPRINT("parse failed"));
77661 duk_pop(ctx);
77662 duk_push_nan(ctx);
77663 return;
77664
77665 parse_explimit_error:
77666 DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value"));
77667 DUK_ERROR_RANGE(thr, "exponent too large");
77668 return;
77669}
77670#line 1 "duk_regexp_compiler.c"
77671/*
77672 * Regexp compilation.
77673 *
77674 * See doc/regexp.rst for a discussion of the compilation approach and
77675 * current limitations.
77676 *
77677 * Regexp bytecode assumes jumps can be expressed with signed 32-bit
77678 * integers. Consequently the bytecode size must not exceed 0x7fffffffL.
77679 * The implementation casts duk_size_t (buffer size) to duk_(u)int32_t
77680 * in many places. Although this could be changed, the bytecode format
77681 * limit would still prevent regexps exceeding the signed 32-bit limit
77682 * from working.
77683 *
77684 * XXX: The implementation does not prevent bytecode from exceeding the
77685 * maximum supported size. This could be done by limiting the maximum
77686 * input string size (assuming an upper bound can be computed for number
77687 * of bytecode bytes emitted per input byte) or checking buffer maximum
77688 * size when emitting bytecode (slower).
77689 */
77690
77691/* include removed: duk_internal.h */
77692
77693#ifdef DUK_USE_REGEXP_SUPPORT
77694
77695/*
77696 * Helper macros
77697 */
77698
77699#define DUK__RE_INITIAL_BUFSIZE 64
77700
77701#undef DUK__RE_BUFLEN
77702#define DUK__RE_BUFLEN(re_ctx) \
77703 DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw)
77704
77705/*
77706 * Disjunction struct: result of parsing a disjunction
77707 */
77708
77709typedef struct {
77710 /* Number of characters that the atom matches (e.g. 3 for 'abc'),
77711 * -1 if atom is complex and number of matched characters either
77712 * varies or is not known.
77713 */
77714 duk_int32_t charlen;
77715
77716#if 0
77717 /* These are not needed to implement quantifier capture handling,
77718 * but might be needed at some point.
77719 */
77720
77721 /* re_ctx->captures at start and end of atom parsing.
77722 * Since 'captures' indicates highest capture number emitted
77723 * so far in a DUK_REOP_SAVE, the captures numbers saved by
77724 * the atom are: ]start_captures,end_captures].
77725 */
77726 duk_uint32_t start_captures;
77727 duk_uint32_t end_captures;
77728#endif
77729} duk__re_disjunction_info;
77730
77731/*
77732 * Encoding helpers
77733 *
77734 * Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit
77735 * even though the buffer operations will use duk_size_t.
77736 */
77737
77738/* XXX: the insert helpers should ensure that the bytecode result is not
77739 * larger than expected (or at least assert for it). Many things in the
77740 * bytecode, like skip offsets, won't work correctly if the bytecode is
77741 * larger than say 2G.
77742 */
77743
77744DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) {
77745 if (x < 0) {
77746 return ((duk_uint32_t) (-x)) * 2 + 1;
77747 } else {
77748 return ((duk_uint32_t) x) * 2;
77749 }
77750}
77751
77752/* XXX: return type should probably be duk_size_t, or explicit checks are needed for
77753 * maximum size.
77754 */
77755DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) {
77756 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
77757 duk_small_int_t len;
77758
77759 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
77760 DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, len);
77761 return (duk_uint32_t) len;
77762}
77763
77764DUK_LOCAL duk_uint32_t duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
77765 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
77766 duk_small_int_t len;
77767
77768 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
77769 DUK_BW_WRITE_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, buf, len);
77770 return (duk_uint32_t) len;
77771}
77772
77773DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
77774 return duk__insert_u32(re_ctx, offset, duk__encode_i32(x));
77775}
77776
77777#if 0 /* unused */
77778DUK_LOCAL duk_uint32_t duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
77779 return duk__append_u32(re_ctx, duk__encode_i32(x));
77780}
77781#endif
77782
77783/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
77784DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) {
77785 /* Call sites don't need the result length so it's not accumulated. */
77786 while (count > 0) {
77787 (void) duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
77788 count--;
77789 }
77790}
77791
77792DUK_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) {
77793 DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length);
77794}
77795
77796DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
77797 DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
77798}
77799
77800DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
77801 DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
77802}
77803
77804/*
77805 * Insert a jump offset at 'offset' to complete an instruction
77806 * (the jump offset is always the last component of an instruction).
77807 * The 'skip' argument must be computed relative to 'offset',
77808 * -without- taking into account the skip field being inserted.
77809 *
77810 * ... A B C ins X Y Z ... (ins may be a JUMP, SPLIT1/SPLIT2, etc)
77811 * => ... A B C ins SKIP X Y Z
77812 *
77813 * Computing the final (adjusted) skip value, which is relative to the
77814 * first byte of the next instruction, is a bit tricky because of the
77815 * variable length UTF-8 encoding. See doc/regexp.rst for discussion.
77816 */
77817DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
77818 duk_small_int_t len;
77819
77820 /* XXX: solve into closed form (smaller code) */
77821
77822 if (skip < 0) {
77823 /* two encoding attempts suffices */
77824 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
77825 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
77826 DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */
77827 skip -= (duk_int32_t) len;
77828 }
77829 return duk__insert_i32(re_ctx, offset, skip);
77830}
77831
77832DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) {
77833 return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip);
77834}
77835
77836/*
77837 * duk_re_range_callback for generating character class ranges.
77838 *
77839 * When ignoreCase is false, the range is simply emitted as is.
77840 * We don't, for instance, eliminate duplicates or overlapping
77841 * ranges in a character class.
77842 *
77843 * When ignoreCase is true, the range needs to be normalized through
77844 * canonicalization. Unfortunately a canonicalized version of a
77845 * continuous range is not necessarily continuous (e.g. [x-{] is
77846 * continuous but [X-{] is not). The current algorithm creates the
77847 * canonicalized range(s) space efficiently at the cost of compile
77848 * time execution time (see doc/regexp.rst for discussion).
77849 *
77850 * Note that the ctx->nranges is a context-wide temporary value
77851 * (this is OK because there cannot be multiple character classes
77852 * being parsed simultaneously).
77853 */
77854
77855DUK_LOCAL void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
77856 duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
77857
77858 DUK_DD(DUK_DDPRINT("duk__generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
77859 (void *) re_ctx, (long) r1, (long) r2, (long) direct));
77860
77861 if (!direct && (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE)) {
77862 /*
77863 * Canonicalize a range, generating result ranges as necessary.
77864 * Needs to exhaustively scan the entire range (at most 65536
77865 * code points). If 'direct' is set, caller (lexer) has ensured
77866 * that the range is already canonicalization compatible (this
77867 * is used to avoid unnecessary canonicalization of built-in
77868 * ranges like \W, which are not affected by canonicalization).
77869 *
77870 * NOTE: here is one place where we don't want to support chars
77871 * outside the BMP, because the exhaustive search would be
77872 * massively larger.
77873 */
77874
77875 duk_codepoint_t i;
77876 duk_codepoint_t t;
77877 duk_codepoint_t r_start, r_end;
77878
77879 r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
77880 r_end = r_start;
77881 for (i = r1 + 1; i <= r2; i++) {
77882 t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
77883 if (t == r_end + 1) {
77884 r_end = t;
77885 } else {
77886 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
77887 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
77888 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
77889 re_ctx->nranges++;
77890 r_start = t;
77891 r_end = t;
77892 }
77893 }
77894 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
77895 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
77896 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
77897 re_ctx->nranges++;
77898 } else {
77899 DUK_DD(DUK_DDPRINT("direct, emit range: [%ld,%ld]", (long) r1, (long) r2));
77900 duk__append_u32(re_ctx, (duk_uint32_t) r1);
77901 duk__append_u32(re_ctx, (duk_uint32_t) r2);
77902 re_ctx->nranges++;
77903 }
77904}
77905
77906/*
77907 * Parse regexp Disjunction. Most of regexp compilation happens here.
77908 *
77909 * Handles Disjunction, Alternative, and Term productions directly without
77910 * recursion. The only constructs requiring recursion are positive/negative
77911 * lookaheads, capturing parentheses, and non-capturing parentheses.
77912 *
77913 * The function determines whether the entire disjunction is a 'simple atom'
77914 * (see doc/regexp.rst discussion on 'simple quantifiers') and if so,
77915 * returns the atom character length which is needed by the caller to keep
77916 * track of its own atom character length. A disjunction with more than one
77917 * alternative is never considered a simple atom (although in some cases
77918 * that might be the case).
77919 *
77920 * Return value: simple atom character length or < 0 if not a simple atom.
77921 * Appends the bytecode for the disjunction matcher to the end of the temp
77922 * buffer.
77923 *
77924 * Regexp top level structure is:
77925 *
77926 * Disjunction = Term*
77927 * | Term* | Disjunction
77928 *
77929 * Term = Assertion
77930 * | Atom
77931 * | Atom Quantifier
77932 *
77933 * An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/).
77934 *
77935 * Notes:
77936 *
77937 * * Tracking of the 'simple-ness' of the current atom vs. the entire
77938 * disjunction are separate matters. For instance, the disjunction
77939 * may be complex, but individual atoms may be simple. Furthermore,
77940 * simple quantifiers are used whenever possible, even if the
77941 * disjunction as a whole is complex.
77942 *
77943 * * The estimate of whether an atom is simple is conservative now,
77944 * and it would be possible to expand it. For instance, captures
77945 * cause the disjunction to be marked complex, even though captures
77946 * -can- be handled by simple quantifiers with some minor modifications.
77947 *
77948 * * Disjunction 'tainting' as 'complex' is handled at the end of the
77949 * main for loop collectively for atoms. Assertions, quantifiers,
77950 * and '|' tokens need to taint the result manually if necessary.
77951 * Assertions cannot add to result char length, only atoms (and
77952 * quantifiers) can; currently quantifiers will taint the result
77953 * as complex though.
77954 */
77955
77956DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) {
77957 duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */
77958 duk_int32_t atom_char_length = 0; /* negative -> complex atom */
77959 duk_uint32_t atom_start_captures = re_ctx->captures; /* value of re_ctx->captures at start of atom */
77960 duk_int32_t unpatched_disjunction_split = -1;
77961 duk_int32_t unpatched_disjunction_jump = -1;
77962 duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
77963 duk_int32_t res_charlen = 0; /* -1 if disjunction is complex, char length if simple */
77964 duk__re_disjunction_info tmp_disj;
77965
77966 DUK_ASSERT(out_atom_info != NULL);
77967
77968 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
77969 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT);
77970 }
77971 re_ctx->recursion_depth++;
77972
77973#if 0
77974 out_atom_info->start_captures = re_ctx->captures;
77975#endif
77976
77977 for (;;) {
77978 /* atom_char_length, atom_start_offset, atom_start_offset reflect the
77979 * atom matched on the previous loop. If a quantifier is encountered
77980 * on this loop, these are needed to handle the quantifier correctly.
77981 * new_atom_char_length etc are for the atom parsed on this round;
77982 * they're written to atom_char_length etc at the end of the round.
77983 */
77984 duk_int32_t new_atom_char_length; /* char length of the atom parsed in this loop */
77985 duk_int32_t new_atom_start_offset; /* bytecode start offset of the atom parsed in this loop
77986 * (allows quantifiers to copy the atom bytecode)
77987 */
77988 duk_uint32_t new_atom_start_captures; /* re_ctx->captures at the start of the atom parsed in this loop */
77989
77990 duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token);
77991
77992 DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)",
77993 (long) re_ctx->curr_token.t,
77994 (long) re_ctx->curr_token.num,
77995 (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ?
77996 (int) re_ctx->curr_token.num : (int) '?'));
77997
77998 /* set by atom case clauses */
77999 new_atom_start_offset = -1;
78000 new_atom_char_length = -1;
78001 new_atom_start_captures = re_ctx->captures;
78002
78003 switch (re_ctx->curr_token.t) {
78004 case DUK_RETOK_DISJUNCTION: {
78005 /*
78006 * The handling here is a bit tricky. If a previous '|' has been processed,
78007 * we have a pending split1 and a pending jump (for a previous match). These
78008 * need to be back-patched carefully. See docs for a detailed example.
78009 */
78010
78011 /* patch pending jump and split */
78012 if (unpatched_disjunction_jump >= 0) {
78013 duk_uint32_t offset;
78014
78015 DUK_ASSERT(unpatched_disjunction_split >= 0);
78016 offset = unpatched_disjunction_jump;
78017 offset += duk__insert_jump_offset(re_ctx,
78018 offset,
78019 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
78020 /* offset is now target of the pending split (right after jump) */
78021 duk__insert_jump_offset(re_ctx,
78022 unpatched_disjunction_split,
78023 offset - unpatched_disjunction_split);
78024 }
78025
78026 /* add a new pending split to the beginning of the entire disjunction */
78027 (void) duk__insert_u32(re_ctx,
78028 entry_offset,
78029 DUK_REOP_SPLIT1); /* prefer direct execution */
78030 unpatched_disjunction_split = entry_offset + 1; /* +1 for opcode */
78031
78032 /* add a new pending match jump for latest finished alternative */
78033 duk__append_u32(re_ctx, DUK_REOP_JUMP);
78034 unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78035
78036 /* 'taint' result as complex */
78037 res_charlen = -1;
78038 break;
78039 }
78040 case DUK_RETOK_QUANTIFIER: {
78041 if (atom_start_offset < 0) {
78042 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM);
78043 }
78044 if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) {
78045 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES);
78046 }
78047 if (atom_char_length >= 0) {
78048 /*
78049 * Simple atom
78050 *
78051 * If atom_char_length is zero, we'll have unbounded execution time for e.g.
78052 * /()*x/.exec('x'). We can't just skip the match because it might have some
78053 * side effects (for instance, if we allowed captures in simple atoms, the
78054 * capture needs to happen). The simple solution below is to force the
78055 * quantifier to match at most once, since the additional matches have no effect.
78056 *
78057 * With a simple atom there can be no capture groups, so no captures need
78058 * to be reset.
78059 */
78060 duk_int32_t atom_code_length;
78061 duk_uint32_t offset;
78062 duk_uint32_t qmin, qmax;
78063
78064 qmin = re_ctx->curr_token.qmin;
78065 qmax = re_ctx->curr_token.qmax;
78066 if (atom_char_length == 0) {
78067 /* qmin and qmax will be 0 or 1 */
78068 if (qmin > 1) {
78069 qmin = 1;
78070 }
78071 if (qmax > 1) {
78072 qmax = 1;
78073 }
78074 }
78075
78076 duk__append_u32(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
78077 atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - atom_start_offset);
78078
78079 offset = atom_start_offset;
78080 if (re_ctx->curr_token.greedy) {
78081 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
78082 offset += duk__insert_u32(re_ctx, offset, qmin);
78083 offset += duk__insert_u32(re_ctx, offset, qmax);
78084 offset += duk__insert_u32(re_ctx, offset, atom_char_length);
78085 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
78086 } else {
78087 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
78088 offset += duk__insert_u32(re_ctx, offset, qmin);
78089 offset += duk__insert_u32(re_ctx, offset, qmax);
78090 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
78091 }
78092 DUK_UNREF(offset); /* silence scan-build warning */
78093 } else {
78094 /*
78095 * Complex atom
78096 *
78097 * The original code is used as a template, and removed at the end
78098 * (this differs from the handling of simple quantifiers).
78099 *
78100 * NOTE: there is no current solution for empty atoms in complex
78101 * quantifiers. This would need some sort of a 'progress' instruction.
78102 *
78103 * XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies?
78104 */
78105 duk_int32_t atom_code_length;
78106 duk_uint32_t atom_copies;
78107 duk_uint32_t tmp_qmin, tmp_qmax;
78108
78109 /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */
78110 atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ?
78111 re_ctx->curr_token.qmin : re_ctx->curr_token.qmax;
78112 if (atom_copies > DUK_RE_MAX_ATOM_COPIES) {
78113 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES);
78114 }
78115
78116 /* wipe the capture range made by the atom (if any) */
78117 DUK_ASSERT(atom_start_captures <= re_ctx->captures);
78118 if (atom_start_captures != re_ctx->captures) {
78119 DUK_ASSERT(atom_start_captures < re_ctx->captures);
78120 DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]",
78121 (long) atom_start_captures, (long) re_ctx->captures));
78122
78123 /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
78124 duk__insert_u32(re_ctx, atom_start_offset, (re_ctx->captures - atom_start_captures) * 2);
78125 duk__insert_u32(re_ctx, atom_start_offset, (atom_start_captures + 1) * 2);
78126 duk__insert_u32(re_ctx, atom_start_offset, DUK_REOP_WIPERANGE);
78127 } else {
78128 DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
78129 (long) atom_start_captures));
78130 }
78131
78132 atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset;
78133
78134 /* insert the required matches (qmin) by copying the atom */
78135 tmp_qmin = re_ctx->curr_token.qmin;
78136 tmp_qmax = re_ctx->curr_token.qmax;
78137 while (tmp_qmin > 0) {
78138 duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
78139 tmp_qmin--;
78140 if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
78141 tmp_qmax--;
78142 }
78143 }
78144 DUK_ASSERT(tmp_qmin == 0);
78145
78146 /* insert code for matching the remainder - infinite or finite */
78147 if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) {
78148 /* reuse last emitted atom for remaining 'infinite' quantifier */
78149
78150 if (re_ctx->curr_token.qmin == 0) {
78151 /* Special case: original qmin was zero so there is nothing
78152 * to repeat. Emit an atom copy but jump over it here.
78153 */
78154 duk__append_u32(re_ctx, DUK_REOP_JUMP);
78155 duk__append_jump_offset(re_ctx, atom_code_length);
78156 duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
78157 }
78158 if (re_ctx->curr_token.greedy) {
78159 duk__append_u32(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
78160 } else {
78161 duk__append_u32(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */
78162 }
78163 duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */
78164 } else {
78165 /*
78166 * The remaining matches are emitted as sequence of SPLITs and atom
78167 * copies; the SPLITs skip the remaining copies and match the sequel.
78168 * This sequence needs to be emitted starting from the last copy
78169 * because the SPLITs are variable length due to the variable length
78170 * skip offset. This causes a lot of memory copying now.
78171 *
78172 * Example structure (greedy, match maximum # atoms):
78173 *
78174 * SPLIT1 LSEQ
78175 * (atom)
78176 * SPLIT1 LSEQ ; <- the byte length of this instruction is needed
78177 * (atom) ; to encode the above SPLIT1 correctly
78178 * ...
78179 * LSEQ:
78180 */
78181 duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
78182 while (tmp_qmax > 0) {
78183 duk__insert_slice(re_ctx, offset, atom_start_offset, atom_code_length);
78184 if (re_ctx->curr_token.greedy) {
78185 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */
78186 } else {
78187 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2); /* prefer jump */
78188 }
78189 duk__insert_jump_offset(re_ctx,
78190 offset + 1, /* +1 for opcode */
78191 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
78192 tmp_qmax--;
78193 }
78194 }
78195
78196 /* remove the original 'template' atom */
78197 duk__remove_slice(re_ctx, atom_start_offset, atom_code_length);
78198 }
78199
78200 /* 'taint' result as complex */
78201 res_charlen = -1;
78202 break;
78203 }
78204 case DUK_RETOK_ASSERT_START: {
78205 duk__append_u32(re_ctx, DUK_REOP_ASSERT_START);
78206 break;
78207 }
78208 case DUK_RETOK_ASSERT_END: {
78209 duk__append_u32(re_ctx, DUK_REOP_ASSERT_END);
78210 break;
78211 }
78212 case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
78213 duk__append_u32(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
78214 break;
78215 }
78216 case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
78217 duk__append_u32(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
78218 break;
78219 }
78220 case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
78221 case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: {
78222 duk_uint32_t offset;
78223 duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ?
78224 DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG;
78225
78226 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
78227 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
78228 duk__append_u32(re_ctx, DUK_REOP_MATCH);
78229
78230 (void) duk__insert_u32(re_ctx, offset, opcode);
78231 (void) duk__insert_jump_offset(re_ctx,
78232 offset + 1, /* +1 for opcode */
78233 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
78234
78235 /* 'taint' result as complex -- this is conservative,
78236 * as lookaheads do not backtrack.
78237 */
78238 res_charlen = -1;
78239 break;
78240 }
78241 case DUK_RETOK_ATOM_PERIOD: {
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, DUK_REOP_PERIOD);
78245 break;
78246 }
78247 case DUK_RETOK_ATOM_CHAR: {
78248 /* Note: successive characters could be joined into string matches
78249 * but this is not trivial (consider e.g. '/xyz+/); see docs for
78250 * more discussion.
78251 */
78252 duk_uint32_t ch;
78253
78254 new_atom_char_length = 1;
78255 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78256 duk__append_u32(re_ctx, DUK_REOP_CHAR);
78257 ch = re_ctx->curr_token.num;
78258 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
78259 ch = duk_unicode_re_canonicalize_char(re_ctx->thr, ch);
78260 }
78261 duk__append_u32(re_ctx, ch);
78262 break;
78263 }
78264 case DUK_RETOK_ATOM_DIGIT:
78265 case DUK_RETOK_ATOM_NOT_DIGIT: {
78266 new_atom_char_length = 1;
78267 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78268 duk__append_u32(re_ctx,
78269 (re_ctx->curr_token.t == DUK_RETOK_ATOM_DIGIT) ?
78270 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78271 duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)));
78272 duk__append_u16_list(re_ctx, duk_unicode_re_ranges_digit, sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
78273 break;
78274 }
78275 case DUK_RETOK_ATOM_WHITE:
78276 case DUK_RETOK_ATOM_NOT_WHITE: {
78277 new_atom_char_length = 1;
78278 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78279 duk__append_u32(re_ctx,
78280 (re_ctx->curr_token.t == DUK_RETOK_ATOM_WHITE) ?
78281 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78282 duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)));
78283 duk__append_u16_list(re_ctx, duk_unicode_re_ranges_white, sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
78284 break;
78285 }
78286 case DUK_RETOK_ATOM_WORD_CHAR:
78287 case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
78288 new_atom_char_length = 1;
78289 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78290 duk__append_u32(re_ctx,
78291 (re_ctx->curr_token.t == DUK_RETOK_ATOM_WORD_CHAR) ?
78292 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78293 duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t)));
78294 duk__append_u16_list(re_ctx, duk_unicode_re_ranges_wordchar, sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
78295 break;
78296 }
78297 case DUK_RETOK_ATOM_BACKREFERENCE: {
78298 duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num;
78299 if (backref > re_ctx->highest_backref) {
78300 re_ctx->highest_backref = backref;
78301 }
78302 new_atom_char_length = -1; /* mark as complex */
78303 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78304 duk__append_u32(re_ctx, DUK_REOP_BACKREFERENCE);
78305 duk__append_u32(re_ctx, backref);
78306 break;
78307 }
78308 case DUK_RETOK_ATOM_START_CAPTURE_GROUP: {
78309 duk_uint32_t cap;
78310
78311 new_atom_char_length = -1; /* mark as complex (capture handling) */
78312 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78313 cap = ++re_ctx->captures;
78314 duk__append_u32(re_ctx, DUK_REOP_SAVE);
78315 duk__append_u32(re_ctx, cap * 2);
78316 duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */
78317 duk__append_u32(re_ctx, DUK_REOP_SAVE);
78318 duk__append_u32(re_ctx, cap * 2 + 1);
78319 break;
78320 }
78321 case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: {
78322 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78323 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
78324 new_atom_char_length = tmp_disj.charlen;
78325 break;
78326 }
78327 case DUK_RETOK_ATOM_START_CHARCLASS:
78328 case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: {
78329 /*
78330 * Range parsing is done with a special lexer function which calls
78331 * us for every range parsed. This is different from how rest of
78332 * the parsing works, but avoids a heavy, arbitrary size intermediate
78333 * value type to hold the ranges.
78334 *
78335 * Another complication is the handling of character ranges when
78336 * case insensitive matching is used (see docs for discussion).
78337 * The range handler callback given to the lexer takes care of this
78338 * as well.
78339 *
78340 * Note that duplicate ranges are not eliminated when parsing character
78341 * classes, so that canonicalization of
78342 *
78343 * [0-9a-fA-Fx-{]
78344 *
78345 * creates the result (note the duplicate ranges):
78346 *
78347 * [0-9A-FA-FX-Z{-{]
78348 *
78349 * where [x-{] is split as a result of canonicalization. The duplicate
78350 * ranges are not a semantics issue: they work correctly.
78351 */
78352
78353 duk_uint32_t offset;
78354
78355 DUK_DD(DUK_DDPRINT("character class"));
78356
78357 /* insert ranges instruction, range count patched in later */
78358 new_atom_char_length = 1;
78359 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78360 duk__append_u32(re_ctx,
78361 (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
78362 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78363 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */
78364
78365 /* parse ranges until character class ends */
78366 re_ctx->nranges = 0; /* note: ctx-wide temporary */
78367 duk_lexer_parse_re_ranges(&re_ctx->lex, duk__generate_ranges, (void *) re_ctx);
78368
78369 /* insert range count */
78370 duk__insert_u32(re_ctx, offset, re_ctx->nranges);
78371 break;
78372 }
78373 case DUK_RETOK_ATOM_END_GROUP: {
78374 if (expect_eof) {
78375 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN);
78376 }
78377 goto done;
78378 }
78379 case DUK_RETOK_EOF: {
78380 if (!expect_eof) {
78381 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN);
78382 }
78383 goto done;
78384 }
78385 default: {
78386 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN);
78387 }
78388 }
78389
78390 /* a complex (new) atom taints the result */
78391 if (new_atom_start_offset >= 0) {
78392 if (new_atom_char_length < 0) {
78393 res_charlen = -1;
78394 } else if (res_charlen >= 0) {
78395 /* only advance if not tainted */
78396 res_charlen += new_atom_char_length;
78397 }
78398 }
78399
78400 /* record previous atom info in case next token is a quantifier */
78401 atom_start_offset = new_atom_start_offset;
78402 atom_char_length = new_atom_char_length;
78403 atom_start_captures = new_atom_start_captures;
78404 }
78405
78406 done:
78407
78408 /* finish up pending jump and split for last alternative */
78409 if (unpatched_disjunction_jump >= 0) {
78410 duk_uint32_t offset;
78411
78412 DUK_ASSERT(unpatched_disjunction_split >= 0);
78413 offset = unpatched_disjunction_jump;
78414 offset += duk__insert_jump_offset(re_ctx,
78415 offset,
78416 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
78417 /* offset is now target of the pending split (right after jump) */
78418 duk__insert_jump_offset(re_ctx,
78419 unpatched_disjunction_split,
78420 offset - unpatched_disjunction_split);
78421 }
78422
78423#if 0
78424 out_atom_info->end_captures = re_ctx->captures;
78425#endif
78426 out_atom_info->charlen = res_charlen;
78427 DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld",
78428 (long) out_atom_info->charlen));
78429
78430 re_ctx->recursion_depth--;
78431}
78432
78433/*
78434 * Flags parsing (see E5 Section 15.10.4.1).
78435 */
78436
78437DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
78438 const duk_uint8_t *p;
78439 const duk_uint8_t *p_end;
78440 duk_uint32_t flags = 0;
78441
78442 p = DUK_HSTRING_GET_DATA(h);
78443 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
78444
78445 /* Note: can be safely scanned as bytes (undecoded) */
78446
78447 while (p < p_end) {
78448 duk_uint8_t c = *p++;
78449 switch ((int) c) {
78450 case (int) 'g': {
78451 if (flags & DUK_RE_FLAG_GLOBAL) {
78452 goto error;
78453 }
78454 flags |= DUK_RE_FLAG_GLOBAL;
78455 break;
78456 }
78457 case (int) 'i': {
78458 if (flags & DUK_RE_FLAG_IGNORE_CASE) {
78459 goto error;
78460 }
78461 flags |= DUK_RE_FLAG_IGNORE_CASE;
78462 break;
78463 }
78464 case (int) 'm': {
78465 if (flags & DUK_RE_FLAG_MULTILINE) {
78466 goto error;
78467 }
78468 flags |= DUK_RE_FLAG_MULTILINE;
78469 break;
78470 }
78471 default: {
78472 goto error;
78473 }
78474 }
78475 }
78476
78477 return flags;
78478
78479 error:
78480 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS);
78481 return 0; /* never here */
78482}
78483
78484/*
78485 * Create escaped RegExp source (E5 Section 15.10.3).
78486 *
78487 * The current approach is to special case the empty RegExp
78488 * ('' -> '(?:)') and otherwise replace unescaped '/' characters
78489 * with '\/' regardless of where they occur in the regexp.
78490 *
78491 * Note that normalization does not seem to be necessary for
78492 * RegExp literals (e.g. '/foo/') because to be acceptable as
78493 * a RegExp literal, the text between forward slashes must
78494 * already match the escaping requirements (e.g. must not contain
78495 * unescaped forward slashes or be empty). Escaping IS needed
78496 * for expressions like 'new Regexp("...", "")' however.
78497 * Currently, we re-escape in either case.
78498 *
78499 * Also note that we process the source here in UTF-8 encoded
78500 * form. This is correct, because any non-ASCII characters are
78501 * passed through without change.
78502 */
78503
78504DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
78505 duk_context *ctx = (duk_context *) thr;
78506 duk_hstring *h;
78507 const duk_uint8_t *p;
78508 duk_bufwriter_ctx bw_alloc;
78509 duk_bufwriter_ctx *bw;
78510 duk_uint8_t *q;
78511 duk_size_t i, n;
78512 duk_uint_fast8_t c_prev, c;
78513
78514 h = duk_get_hstring(ctx, idx_pattern);
78515 DUK_ASSERT(h != NULL);
78516 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
78517 n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
78518
78519 if (n == 0) {
78520 /* return '(?:)' */
78521 duk_push_hstring_stridx(ctx, DUK_STRIDX_ESCAPED_EMPTY_REGEXP);
78522 return;
78523 }
78524
78525 bw = &bw_alloc;
78526 DUK_BW_INIT_PUSHBUF(thr, bw, n);
78527 q = DUK_BW_GET_PTR(thr, bw);
78528
78529 c_prev = (duk_uint_fast8_t) 0;
78530
78531 for (i = 0; i < n; i++) {
78532 c = p[i];
78533
78534 q = DUK_BW_ENSURE_RAW(thr, bw, 2, q);
78535
78536 if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') {
78537 /* Unescaped '/' ANYWHERE in the regexp (in disjunction,
78538 * inside a character class, ...) => same escape works.
78539 */
78540 *q++ = DUK_ASC_BACKSLASH;
78541 }
78542 *q++ = (duk_uint8_t) c;
78543
78544 c_prev = c;
78545 }
78546
78547 DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
78548 duk_to_string(ctx, -1); /* -> [ ... escaped_source ] */
78549}
78550
78551/*
78552 * Exposed regexp compilation primitive.
78553 *
78554 * Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the
78555 * actual parsing. Handles generation of the compiled regexp header and the
78556 * "boilerplate" capture of the matching substring (save 0 and 1). Also does some
78557 * global level regexp checks after recursive compilation has finished.
78558 *
78559 * An escaped version of the regexp source, suitable for use as a RegExp instance
78560 * 'source' property (see E5 Section 15.10.3), is also left on the stack.
78561 *
78562 * Input stack: [ pattern flags ]
78563 * Output stack: [ bytecode escaped_source ] (both as strings)
78564 */
78565
78566DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
78567 duk_context *ctx = (duk_context *) thr;
78568 duk_re_compiler_ctx re_ctx;
78569 duk_lexer_point lex_point;
78570 duk_hstring *h_pattern;
78571 duk_hstring *h_flags;
78572 duk__re_disjunction_info ign_disj;
78573
78574 DUK_ASSERT(thr != NULL);
78575 DUK_ASSERT(ctx != NULL);
78576
78577 /*
78578 * Args validation
78579 */
78580
78581 /* TypeError if fails */
78582 h_pattern = duk_require_hstring(ctx, -2);
78583 h_flags = duk_require_hstring(ctx, -1);
78584
78585 /*
78586 * Create normalized 'source' property (E5 Section 15.10.3).
78587 */
78588
78589 /* [ ... pattern flags ] */
78590
78591 duk__create_escaped_source(thr, -2);
78592
78593 /* [ ... pattern flags escaped_source ] */
78594
78595 /*
78596 * Init compilation context
78597 */
78598
78599 /* [ ... pattern flags escaped_source buffer ] */
78600
78601 DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
78602 DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */
78603 re_ctx.thr = thr;
78604 re_ctx.lex.thr = thr;
78605 re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
78606 re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
78607 re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
78608 re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT;
78609 re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);
78610
78611 DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE);
78612
78613 DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld",
78614 (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit));
78615
78616 /*
78617 * Init lexer
78618 */
78619
78620 lex_point.offset = 0; /* expensive init, just want to fill window */
78621 lex_point.line = 1;
78622 DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);
78623
78624 /*
78625 * Compilation
78626 */
78627
78628 DUK_DD(DUK_DDPRINT("starting regexp compilation"));
78629
78630 duk__append_u32(&re_ctx, DUK_REOP_SAVE);
78631 duk__append_u32(&re_ctx, 0);
78632 duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
78633 duk__append_u32(&re_ctx, DUK_REOP_SAVE);
78634 duk__append_u32(&re_ctx, 1);
78635 duk__append_u32(&re_ctx, DUK_REOP_MATCH);
78636
78637 /*
78638 * Check for invalid backreferences; note that it is NOT an error
78639 * to back-reference a capture group which has not yet been introduced
78640 * in the pattern (as in /\1(foo)/); in fact, the backreference will
78641 * always match! It IS an error to back-reference a capture group
78642 * which will never be introduced in the pattern. Thus, we can check
78643 * for such references only after parsing is complete.
78644 */
78645
78646 if (re_ctx.highest_backref > re_ctx.captures) {
78647 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS);
78648 }
78649
78650 /*
78651 * Emit compiled regexp header: flags, ncaptures
78652 * (insertion order inverted on purpose)
78653 */
78654
78655 duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
78656 duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);
78657
78658 /* [ ... pattern flags escaped_source buffer ] */
78659
78660 DUK_BW_COMPACT(thr, &re_ctx.bw);
78661 duk_to_string(ctx, -1); /* coerce to string */
78662
78663 /* [ ... pattern flags escaped_source bytecode ] */
78664
78665 /*
78666 * Finalize stack
78667 */
78668
78669 duk_remove(ctx, -4); /* -> [ ... flags escaped_source bytecode ] */
78670 duk_remove(ctx, -3); /* -> [ ... escaped_source bytecode ] */
78671
78672 DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
78673 (duk_tval *) duk_get_tval(ctx, -1), (duk_tval *) duk_get_tval(ctx, -2)));
78674}
78675
78676/*
78677 * Create a RegExp instance (E5 Section 15.10.7).
78678 *
78679 * Note: the output stack left by duk_regexp_compile() is directly compatible
78680 * with the input here.
78681 *
78682 * Input stack: [ escaped_source bytecode ] (both as strings)
78683 * Output stack: [ RegExp ]
78684 */
78685
78686DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
78687 duk_context *ctx = (duk_context *) thr;
78688 duk_hobject *h;
78689 duk_hstring *h_bc;
78690 duk_small_int_t re_flags;
78691
78692 /* [ ... escape_source bytecode ] */
78693
78694 h_bc = duk_get_hstring(ctx, -1);
78695 DUK_ASSERT(h_bc != NULL);
78696 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1); /* always at least the header */
78697 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
78698 DUK_ASSERT((duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80); /* flags always encodes to 1 byte */
78699 re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
78700
78701 /* [ ... escaped_source bytecode ] */
78702
78703 duk_push_object(ctx);
78704 h = duk_get_hobject(ctx, -1);
78705 DUK_ASSERT(h != NULL);
78706 duk_insert(ctx, -3);
78707
78708 /* [ ... regexp_object escaped_source bytecode ] */
78709
78710 DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
78711 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
78712
78713 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
78714
78715 /* [ ... regexp_object escaped_source ] */
78716
78717 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_SOURCE, DUK_PROPDESC_FLAGS_NONE);
78718
78719 /* [ ... regexp_object ] */
78720
78721 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL));
78722 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_GLOBAL, DUK_PROPDESC_FLAGS_NONE);
78723
78724 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
78725 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_IGNORE_CASE, DUK_PROPDESC_FLAGS_NONE);
78726
78727 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE));
78728 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MULTILINE, DUK_PROPDESC_FLAGS_NONE);
78729
78730 duk_push_int(ctx, 0);
78731 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
78732
78733 /* [ ... regexp_object ] */
78734}
78735
78736#undef DUK__RE_BUFLEN
78737
78738#else /* DUK_USE_REGEXP_SUPPORT */
78739
78740/* regexp support disabled */
78741
78742#endif /* DUK_USE_REGEXP_SUPPORT */
78743#line 1 "duk_regexp_executor.c"
78744/*
78745 * Regexp executor.
78746 *
78747 * Safety: the Ecmascript executor should prevent user from reading and
78748 * replacing regexp bytecode. Even so, the executor must validate all
78749 * memory accesses etc. When an invalid access is detected (e.g. a 'save'
78750 * opcode to invalid, unallocated index) it should fail with an internal
78751 * error but not cause a segmentation fault.
78752 *
78753 * Notes:
78754 *
78755 * - Backtrack counts are limited to unsigned 32 bits but should
78756 * technically be duk_size_t for strings longer than 4G chars.
78757 * This also requires a regexp bytecode change.
78758 */
78759
78760/* include removed: duk_internal.h */
78761
78762#ifdef DUK_USE_REGEXP_SUPPORT
78763
78764/*
78765 * Helpers for UTF-8 handling
78766 *
78767 * For bytecode readers the duk_uint32_t and duk_int32_t types are correct
78768 * because they're used for more than just codepoints.
78769 */
78770
78771DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
78772 return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
78773}
78774
78775DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
78776 duk_uint32_t t;
78777
78778 /* signed integer encoding needed to work with UTF-8 */
78779 t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
78780 if (t & 1) {
78781 return -((duk_int32_t) (t >> 1));
78782 } else {
78783 return (duk_int32_t) (t >> 1);
78784 }
78785}
78786
78787DUK_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) {
78788 const duk_uint8_t *p;
78789
78790 /* Note: allow backtracking from p == ptr_end */
78791 p = *ptr;
78792 if (p < ptr_start || p > ptr_end) {
78793 goto fail;
78794 }
78795
78796 while (count > 0) {
78797 for (;;) {
78798 p--;
78799 if (p < ptr_start) {
78800 goto fail;
78801 }
78802 if ((*p & 0xc0) != 0x80) {
78803 /* utf-8 continuation bytes have the form 10xx xxxx */
78804 break;
78805 }
78806 }
78807 count--;
78808 }
78809 *ptr = p;
78810 return p;
78811
78812 fail:
78813 DUK_ERROR_INTERNAL_DEFMSG(thr);
78814 return NULL; /* never here */
78815}
78816
78817DUK_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) {
78818 const duk_uint8_t *p;
78819
78820 p = *ptr;
78821 if (p < ptr_start || p >= ptr_end) {
78822 goto fail;
78823 }
78824
78825 while (count > 0) {
78826 for (;;) {
78827 p++;
78828
78829 /* Note: if encoding ends by hitting end of input, we don't check that
78830 * the encoding is valid, we just assume it is.
78831 */
78832 if (p >= ptr_end || ((*p & 0xc0) != 0x80)) {
78833 /* utf-8 continuation bytes have the form 10xx xxxx */
78834 break;
78835 }
78836 }
78837 count--;
78838 }
78839
78840 *ptr = p;
78841 return p;
78842
78843 fail:
78844 DUK_ERROR_INTERNAL_DEFMSG(thr);
78845 return NULL; /* never here */
78846}
78847
78848/*
78849 * Helpers for dealing with the input string
78850 */
78851
78852/* Get a (possibly canonicalized) input character from current sp. The input
78853 * itself is never modified, and captures always record non-canonicalized
78854 * characters even in case-insensitive matching.
78855 */
78856DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) {
78857 duk_codepoint_t res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
78858 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
78859 res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
78860 }
78861 return res;
78862}
78863
78864DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) {
78865 return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count);
78866}
78867
78868/* Backtrack utf-8 input and return a (possibly canonicalized) input character. */
78869DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) {
78870 /* note: caller 'sp' is intentionally not updated here */
78871 (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1);
78872 return duk__inp_get_cp(re_ctx, &sp);
78873}
78874
78875/*
78876 * Regexp recursive matching function.
78877 *
78878 * Returns 'sp' on successful match (points to character after last matched one),
78879 * NULL otherwise.
78880 *
78881 * The C recursion depth limit check is only performed in this function, this
78882 * suffices because the function is present in all true recursion required by
78883 * regexp execution.
78884 */
78885
78886DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) {
78887 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
78888 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT);
78889 }
78890 re_ctx->recursion_depth++;
78891
78892 for (;;) {
78893 duk_small_int_t op;
78894
78895 if (re_ctx->steps_count >= re_ctx->steps_limit) {
78896 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT);
78897 }
78898 re_ctx->steps_count++;
78899
78900 op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
78901
78902 DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld",
78903 (long) re_ctx->recursion_depth,
78904 (long) re_ctx->steps_count,
78905 (long) (pc - re_ctx->bytecode),
78906 (long) (sp - re_ctx->input),
78907 (long) op));
78908
78909 switch (op) {
78910 case DUK_REOP_MATCH: {
78911 goto match;
78912 }
78913 case DUK_REOP_CHAR: {
78914 /*
78915 * Byte-based matching would be possible for case-sensitive
78916 * matching but not for case-insensitive matching. So, we
78917 * match by decoding the input and bytecode character normally.
78918 *
78919 * Bytecode characters are assumed to be already canonicalized.
78920 * Input characters are canonicalized automatically by
78921 * duk__inp_get_cp() if necessary.
78922 *
78923 * There is no opcode for matching multiple characters. The
78924 * regexp compiler has trouble joining strings efficiently
78925 * during compilation. See doc/regexp.rst for more discussion.
78926 */
78927 duk_codepoint_t c1, c2;
78928
78929 c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
78930 DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
78931 c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */
78932 if (sp >= re_ctx->input_end) {
78933 goto fail;
78934 }
78935 c2 = duk__inp_get_cp(re_ctx, &sp);
78936 DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2));
78937 if (c1 != c2) {
78938 goto fail;
78939 }
78940 break;
78941 }
78942 case DUK_REOP_PERIOD: {
78943 duk_codepoint_t c;
78944
78945 if (sp >= re_ctx->input_end) {
78946 goto fail;
78947 }
78948 c = duk__inp_get_cp(re_ctx, &sp);
78949 if (duk_unicode_is_line_terminator(c)) {
78950 /* E5 Sections 15.10.2.8, 7.3 */
78951 goto fail;
78952 }
78953 break;
78954 }
78955 case DUK_REOP_RANGES:
78956 case DUK_REOP_INVRANGES: {
78957 duk_uint32_t n;
78958 duk_codepoint_t c;
78959 duk_small_int_t match;
78960
78961 n = duk__bc_get_u32(re_ctx, &pc);
78962 if (sp >= re_ctx->input_end) {
78963 goto fail;
78964 }
78965 c = duk__inp_get_cp(re_ctx, &sp);
78966
78967 match = 0;
78968 while (n) {
78969 duk_codepoint_t r1, r2;
78970 r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
78971 r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
78972 DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld",
78973 (long) n, (long) r1, (long) r2, (long) c));
78974 if (c >= r1 && c <= r2) {
78975 /* Note: don't bail out early, we must read all the ranges from
78976 * bytecode. Another option is to skip them efficiently after
78977 * breaking out of here. Prefer smallest code.
78978 */
78979 match = 1;
78980 }
78981 n--;
78982 }
78983
78984 if (op == DUK_REOP_RANGES) {
78985 if (!match) {
78986 goto fail;
78987 }
78988 } else {
78989 DUK_ASSERT(op == DUK_REOP_INVRANGES);
78990 if (match) {
78991 goto fail;
78992 }
78993 }
78994 break;
78995 }
78996 case DUK_REOP_ASSERT_START: {
78997 duk_codepoint_t c;
78998
78999 if (sp <= re_ctx->input) {
79000 break;
79001 }
79002 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
79003 goto fail;
79004 }
79005 c = duk__inp_get_prev_cp(re_ctx, sp);
79006 if (duk_unicode_is_line_terminator(c)) {
79007 /* E5 Sections 15.10.2.8, 7.3 */
79008 break;
79009 }
79010 goto fail;
79011 }
79012 case DUK_REOP_ASSERT_END: {
79013 duk_codepoint_t c;
79014 const duk_uint8_t *tmp_sp;
79015
79016 if (sp >= re_ctx->input_end) {
79017 break;
79018 }
79019 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
79020 goto fail;
79021 }
79022 tmp_sp = sp;
79023 c = duk__inp_get_cp(re_ctx, &tmp_sp);
79024 if (duk_unicode_is_line_terminator(c)) {
79025 /* E5 Sections 15.10.2.8, 7.3 */
79026 break;
79027 }
79028 goto fail;
79029 }
79030 case DUK_REOP_ASSERT_WORD_BOUNDARY:
79031 case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: {
79032 /*
79033 * E5 Section 15.10.2.6. The previous and current character
79034 * should -not- be canonicalized as they are now. However,
79035 * canonicalization does not affect the result of IsWordChar()
79036 * (which depends on Unicode characters never canonicalizing
79037 * into ASCII characters) so this does not matter.
79038 */
79039 duk_small_int_t w1, w2;
79040
79041 if (sp <= re_ctx->input) {
79042 w1 = 0; /* not a wordchar */
79043 } else {
79044 duk_codepoint_t c;
79045 c = duk__inp_get_prev_cp(re_ctx, sp);
79046 w1 = duk_unicode_re_is_wordchar(c);
79047 }
79048 if (sp >= re_ctx->input_end) {
79049 w2 = 0; /* not a wordchar */
79050 } else {
79051 const duk_uint8_t *tmp_sp = sp; /* dummy so sp won't get updated */
79052 duk_codepoint_t c;
79053 c = duk__inp_get_cp(re_ctx, &tmp_sp);
79054 w2 = duk_unicode_re_is_wordchar(c);
79055 }
79056
79057 if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) {
79058 if (w1 == w2) {
79059 goto fail;
79060 }
79061 } else {
79062 DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
79063 if (w1 != w2) {
79064 goto fail;
79065 }
79066 }
79067 break;
79068 }
79069 case DUK_REOP_JUMP: {
79070 duk_int32_t skip;
79071
79072 skip = duk__bc_get_i32(re_ctx, &pc);
79073 pc += skip;
79074 break;
79075 }
79076 case DUK_REOP_SPLIT1: {
79077 /* split1: prefer direct execution (no jump) */
79078 const duk_uint8_t *sub_sp;
79079 duk_int32_t skip;
79080
79081 skip = duk__bc_get_i32(re_ctx, &pc);
79082 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79083 if (sub_sp) {
79084 sp = sub_sp;
79085 goto match;
79086 }
79087 pc += skip;
79088 break;
79089 }
79090 case DUK_REOP_SPLIT2: {
79091 /* split2: prefer jump execution (not direct) */
79092 const duk_uint8_t *sub_sp;
79093 duk_int32_t skip;
79094
79095 skip = duk__bc_get_i32(re_ctx, &pc);
79096 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
79097 if (sub_sp) {
79098 sp = sub_sp;
79099 goto match;
79100 }
79101 break;
79102 }
79103 case DUK_REOP_SQMINIMAL: {
79104 duk_uint32_t q, qmin, qmax;
79105 duk_int32_t skip;
79106 const duk_uint8_t *sub_sp;
79107
79108 qmin = duk__bc_get_u32(re_ctx, &pc);
79109 qmax = duk__bc_get_u32(re_ctx, &pc);
79110 skip = duk__bc_get_i32(re_ctx, &pc);
79111 DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld",
79112 (unsigned long) qmin, (unsigned long) qmax, (long) skip));
79113
79114 q = 0;
79115 while (q <= qmax) {
79116 if (q >= qmin) {
79117 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
79118 if (sub_sp) {
79119 sp = sub_sp;
79120 goto match;
79121 }
79122 }
79123 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79124 if (!sub_sp) {
79125 break;
79126 }
79127 sp = sub_sp;
79128 q++;
79129 }
79130 goto fail;
79131 }
79132 case DUK_REOP_SQGREEDY: {
79133 duk_uint32_t q, qmin, qmax, atomlen;
79134 duk_int32_t skip;
79135 const duk_uint8_t *sub_sp;
79136
79137 qmin = duk__bc_get_u32(re_ctx, &pc);
79138 qmax = duk__bc_get_u32(re_ctx, &pc);
79139 atomlen = duk__bc_get_u32(re_ctx, &pc);
79140 skip = duk__bc_get_i32(re_ctx, &pc);
79141 DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld",
79142 (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip));
79143
79144 q = 0;
79145 while (q < qmax) {
79146 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79147 if (!sub_sp) {
79148 break;
79149 }
79150 sp = sub_sp;
79151 q++;
79152 }
79153 while (q >= qmin) {
79154 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
79155 if (sub_sp) {
79156 sp = sub_sp;
79157 goto match;
79158 }
79159 if (q == qmin) {
79160 break;
79161 }
79162
79163 /* Note: if atom were to contain e.g. captures, we would need to
79164 * re-match the atom to get correct captures. Simply quantifiers
79165 * do not allow captures in their atom now, so this is not an issue.
79166 */
79167
79168 DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)",
79169 (long) atomlen));
79170 sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen);
79171 q--;
79172 }
79173 goto fail;
79174 }
79175 case DUK_REOP_SAVE: {
79176 duk_uint32_t idx;
79177 const duk_uint8_t *old;
79178 const duk_uint8_t *sub_sp;
79179
79180 idx = duk__bc_get_u32(re_ctx, &pc);
79181 if (idx >= re_ctx->nsaved) {
79182 /* idx is unsigned, < 0 check is not necessary */
79183 DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld", (long) idx));
79184 goto internal_error;
79185 }
79186 old = re_ctx->saved[idx];
79187 re_ctx->saved[idx] = sp;
79188 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79189 if (sub_sp) {
79190 sp = sub_sp;
79191 goto match;
79192 }
79193 re_ctx->saved[idx] = old;
79194 goto fail;
79195 }
79196 case DUK_REOP_WIPERANGE: {
79197 /* Wipe capture range and save old values for backtracking.
79198 *
79199 * XXX: this typically happens with a relatively small idx_count.
79200 * It might be useful to handle cases where the count is small
79201 * (say <= 8) by saving the values in stack instead. This would
79202 * reduce memory churn and improve performance, at the cost of a
79203 * slightly higher code footprint.
79204 */
79205 duk_uint32_t idx_start, idx_count;
79206#ifdef DUK_USE_EXPLICIT_NULL_INIT
79207 duk_uint32_t idx_end, idx;
79208#endif
79209 duk_uint8_t **range_save;
79210 const duk_uint8_t *sub_sp;
79211
79212 idx_start = duk__bc_get_u32(re_ctx, &pc);
79213 idx_count = duk__bc_get_u32(re_ctx, &pc);
79214 DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])",
79215 (long) idx_start, (long) idx_count,
79216 (long) idx_start, (long) (idx_start + idx_count - 1),
79217 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
79218 if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) {
79219 /* idx is unsigned, < 0 check is not necessary */
79220 DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld",
79221 (long) idx_start, (long) idx_count));
79222 goto internal_error;
79223 }
79224 DUK_ASSERT(idx_count > 0);
79225
79226 duk_require_stack((duk_context *) re_ctx->thr, 1);
79227 range_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
79228 sizeof(duk_uint8_t *) * idx_count);
79229 DUK_ASSERT(range_save != NULL);
79230 DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
79231#ifdef DUK_USE_EXPLICIT_NULL_INIT
79232 idx_end = idx_start + idx_count;
79233 for (idx = idx_start; idx < idx_end; idx++) {
79234 re_ctx->saved[idx] = NULL;
79235 }
79236#else
79237 DUK_MEMZERO((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count);
79238#endif
79239
79240 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79241 if (sub_sp) {
79242 /* match: keep wiped/resaved values */
79243 DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
79244 (long) idx_start, (long) (idx_start + idx_count - 1),
79245 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
79246 duk_pop((duk_context *) re_ctx->thr);
79247 sp = sub_sp;
79248 goto match;
79249 }
79250
79251 /* fail: restore saves */
79252 DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
79253 (long) idx_start, (long) (idx_start + idx_count - 1),
79254 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
79255 DUK_MEMCPY((void *) (re_ctx->saved + idx_start),
79256 (const void *) range_save,
79257 sizeof(duk_uint8_t *) * idx_count);
79258 duk_pop((duk_context *) re_ctx->thr);
79259 goto fail;
79260 }
79261 case DUK_REOP_LOOKPOS:
79262 case DUK_REOP_LOOKNEG: {
79263 /*
79264 * Needs a save of multiple saved[] entries depending on what range
79265 * may be overwritten. Because the regexp parser does no such analysis,
79266 * we currently save the entire saved array here. Lookaheads are thus
79267 * a bit expensive. Note that the saved array is not needed for just
79268 * the lookahead sub-match, but for the matching of the entire sequel.
79269 *
79270 * The temporary save buffer is pushed on to the valstack to handle
79271 * errors correctly. Each lookahead causes a C recursion and pushes
79272 * more stuff on the value stack. If the C recursion limit is less
79273 * than the value stack spare, there is no need to check the stack.
79274 * We do so regardless, just in case.
79275 */
79276
79277 duk_int32_t skip;
79278 duk_uint8_t **full_save;
79279 const duk_uint8_t *sub_sp;
79280
79281 DUK_ASSERT(re_ctx->nsaved > 0);
79282
79283 duk_require_stack((duk_context *) re_ctx->thr, 1);
79284 full_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
79285 sizeof(duk_uint8_t *) * re_ctx->nsaved);
79286 DUK_ASSERT(full_save != NULL);
79287 DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
79288
79289 skip = duk__bc_get_i32(re_ctx, &pc);
79290 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79291 if (op == DUK_REOP_LOOKPOS) {
79292 if (!sub_sp) {
79293 goto lookahead_fail;
79294 }
79295 } else {
79296 if (sub_sp) {
79297 goto lookahead_fail;
79298 }
79299 }
79300 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
79301 if (sub_sp) {
79302 /* match: keep saves */
79303 duk_pop((duk_context *) re_ctx->thr);
79304 sp = sub_sp;
79305 goto match;
79306 }
79307
79308 /* fall through */
79309
79310 lookahead_fail:
79311 /* fail: restore saves */
79312 DUK_MEMCPY((void *) re_ctx->saved,
79313 (const void *) full_save,
79314 sizeof(duk_uint8_t *) * re_ctx->nsaved);
79315 duk_pop((duk_context *) re_ctx->thr);
79316 goto fail;
79317 }
79318 case DUK_REOP_BACKREFERENCE: {
79319 /*
79320 * Byte matching for back-references would be OK in case-
79321 * sensitive matching. In case-insensitive matching we need
79322 * to canonicalize characters, so back-reference matching needs
79323 * to be done with codepoints instead. So, we just decode
79324 * everything normally here, too.
79325 *
79326 * Note: back-reference index which is 0 or higher than
79327 * NCapturingParens (= number of capturing parens in the
79328 * -entire- regexp) is a compile time error. However, a
79329 * backreference referring to a valid capture which has
79330 * not matched anything always succeeds! See E5 Section
79331 * 15.10.2.9, step 5, sub-step 3.
79332 */
79333 duk_uint32_t idx;
79334 const duk_uint8_t *p;
79335
79336 idx = duk__bc_get_u32(re_ctx, &pc);
79337 idx = idx << 1; /* backref n -> saved indices [n*2, n*2+1] */
79338 if (idx < 2 || idx + 1 >= re_ctx->nsaved) {
79339 /* regexp compiler should catch these */
79340 DUK_D(DUK_DPRINT("internal error, backreference index insane"));
79341 goto internal_error;
79342 }
79343 if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) {
79344 /* capture is 'undefined', always matches! */
79345 DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match",
79346 (long) idx, (long) (idx + 1)));
79347 break;
79348 }
79349 DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]", (long) idx, (long) (idx + 1)));
79350
79351 p = re_ctx->saved[idx];
79352 while (p < re_ctx->saved[idx+1]) {
79353 duk_codepoint_t c1, c2;
79354
79355 /* Note: not necessary to check p against re_ctx->input_end:
79356 * the memory access is checked by duk__inp_get_cp(), while
79357 * valid compiled regexps cannot write a saved[] entry
79358 * which points to outside the string.
79359 */
79360 if (sp >= re_ctx->input_end) {
79361 goto fail;
79362 }
79363 c1 = duk__inp_get_cp(re_ctx, &p);
79364 c2 = duk__inp_get_cp(re_ctx, &sp);
79365 if (c1 != c2) {
79366 goto fail;
79367 }
79368 }
79369 break;
79370 }
79371 default: {
79372 DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld", (long) op));
79373 goto internal_error;
79374 }
79375 }
79376 }
79377
79378 match:
79379 re_ctx->recursion_depth--;
79380 return sp;
79381
79382 fail:
79383 re_ctx->recursion_depth--;
79384 return NULL;
79385
79386 internal_error:
79387 DUK_ERROR_INTERNAL_DEFMSG(re_ctx->thr);
79388 return NULL; /* never here */
79389}
79390
79391/*
79392 * Exposed matcher function which provides the semantics of RegExp.prototype.exec().
79393 *
79394 * RegExp.prototype.test() has the same semantics as exec() but does not return the
79395 * result object (which contains the matching string and capture groups). Currently
79396 * there is no separate test() helper, so a temporary result object is created and
79397 * discarded if test() is needed. This is intentional, to save code space.
79398 *
79399 * Input stack: [ ... re_obj input ]
79400 * Output stack: [ ... result ]
79401 */
79402
79403DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
79404 duk_context *ctx = (duk_context *) thr;
79405 duk_re_matcher_ctx re_ctx;
79406 duk_hobject *h_regexp;
79407 duk_hstring *h_bytecode;
79408 duk_hstring *h_input;
79409 duk_uint8_t *p_buf;
79410 const duk_uint8_t *pc;
79411 const duk_uint8_t *sp;
79412 duk_small_int_t match = 0;
79413 duk_small_int_t global;
79414 duk_uint_fast32_t i;
79415 double d;
79416 duk_uint32_t char_offset;
79417
79418 DUK_ASSERT(thr != NULL);
79419 DUK_ASSERT(ctx != NULL);
79420
79421 DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
79422 (duk_tval *) duk_get_tval(ctx, -2),
79423 (duk_tval *) duk_get_tval(ctx, -1)));
79424
79425 /*
79426 * Regexp instance check, bytecode check, input coercion.
79427 *
79428 * See E5 Section 15.10.6.
79429 */
79430
79431 /* TypeError if wrong; class check, see E5 Section 15.10.6 */
79432 h_regexp = duk_require_hobject_with_class(ctx, -2, DUK_HOBJECT_CLASS_REGEXP);
79433 DUK_ASSERT(h_regexp != NULL);
79434 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
79435 DUK_UNREF(h_regexp);
79436
79437 duk_to_string(ctx, -1);
79438 h_input = duk_get_hstring(ctx, -1);
79439 DUK_ASSERT(h_input != NULL);
79440
79441 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
79442 h_bytecode = duk_require_hstring(ctx, -1); /* no regexp instance should exist without a non-configurable bytecode property */
79443 DUK_ASSERT(h_bytecode != NULL);
79444
79445 /*
79446 * Basic context initialization.
79447 *
79448 * Some init values are read from the bytecode header
79449 * whose format is (UTF-8 codepoints):
79450 *
79451 * uint flags
79452 * uint nsaved (even, 2n+2 where n = num captures)
79453 */
79454
79455 /* [ ... re_obj input bc ] */
79456
79457 DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
79458
79459 re_ctx.thr = thr;
79460 re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
79461 re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
79462 re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
79463 re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
79464 re_ctx.saved = NULL;
79465 re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT;
79466 re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT;
79467
79468 /* read header */
79469 pc = re_ctx.bytecode;
79470 re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc);
79471 re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc);
79472 re_ctx.bytecode = pc;
79473
79474 DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */
79475 global = (duk_small_int_t) (force_global | (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
79476
79477 DUK_ASSERT(re_ctx.nsaved >= 2);
79478 DUK_ASSERT((re_ctx.nsaved % 2) == 0);
79479
79480 p_buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved);
79481 DUK_UNREF(p_buf);
79482 re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
79483 DUK_ASSERT(re_ctx.saved != NULL);
79484
79485 /* [ ... re_obj input bc saved_buf ] */
79486
79487#if defined(DUK_USE_EXPLICIT_NULL_INIT)
79488 for (i = 0; i < re_ctx.nsaved; i++) {
79489 re_ctx.saved[i] = (duk_uint8_t *) NULL;
79490 }
79491#elif defined(DUK_USE_ZERO_BUFFER_DATA)
79492 /* buffer is automatically zeroed */
79493#else
79494 DUK_MEMZERO((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved);
79495#endif
79496
79497 DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld",
79498 (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit,
79499 (long) re_ctx.steps_limit));
79500
79501 /*
79502 * Get starting character offset for match, and initialize 'sp' based on it.
79503 *
79504 * Note: lastIndex is non-configurable so it must be present (we check the
79505 * internal class of the object above, so we know it is). User code can set
79506 * its value to an arbitrary (garbage) value though; E5 requires that lastIndex
79507 * be coerced to a number before using. The code below works even if the
79508 * property is missing: the value will then be coerced to zero.
79509 *
79510 * Note: lastIndex may be outside Uint32 range even after ToInteger() coercion.
79511 * For instance, ToInteger(+Infinity) = +Infinity. We track the match offset
79512 * as an integer, but pre-check it to be inside the 32-bit range before the loop.
79513 * If not, the check in E5 Section 15.10.6.2, step 9.a applies.
79514 */
79515
79516 /* XXX: lastIndex handling produces a lot of asm */
79517
79518 /* [ ... re_obj input bc saved_buf ] */
79519
79520 duk_get_prop_stridx(ctx, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
79521 (void) duk_to_int(ctx, -1); /* ToInteger(lastIndex) */
79522 d = duk_get_number(ctx, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
79523 duk_pop(ctx);
79524
79525 if (global) {
79526 if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
79527 /* match fail */
79528 char_offset = 0; /* not really necessary */
79529 DUK_ASSERT(match == 0);
79530 goto match_over;
79531 }
79532 char_offset = (duk_uint32_t) d;
79533 } else {
79534 /* lastIndex must be ignored for non-global regexps, but get the
79535 * value for (theoretical) side effects. No side effects can
79536 * really occur, because lastIndex is a normal property and is
79537 * always non-configurable for RegExp instances.
79538 */
79539 char_offset = (duk_uint32_t) 0;
79540 }
79541
79542 sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
79543
79544 /*
79545 * Match loop.
79546 *
79547 * Try matching at different offsets until match found or input exhausted.
79548 */
79549
79550 /* [ ... re_obj input bc saved_buf ] */
79551
79552 DUK_ASSERT(match == 0);
79553
79554 for (;;) {
79555 /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */
79556 DUK_ASSERT_DISABLE(char_offset >= 0);
79557 DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
79558
79559 /* Note: ctx.steps is intentionally not reset, it applies to the entire unanchored match */
79560 DUK_ASSERT(re_ctx.recursion_depth == 0);
79561
79562 DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
79563 (long) char_offset, (const void *) sp,
79564 (const void *) re_ctx.input, (const void *) re_ctx.input_end));
79565
79566 /*
79567 * Note:
79568 *
79569 * - duk__match_regexp() is required not to longjmp() in ordinary "non-match"
79570 * conditions; a longjmp() will terminate the entire matching process.
79571 *
79572 * - Clearing saved[] is not necessary because backtracking does it
79573 *
79574 * - Backtracking also rewinds ctx.recursion back to zero, unless an
79575 * internal/limit error occurs (which causes a longjmp())
79576 *
79577 * - If we supported anchored matches, we would break out here
79578 * unconditionally; however, Ecmascript regexps don't have anchored
79579 * matches. It might make sense to implement a fast bail-out if
79580 * the regexp begins with '^' and sp is not 0: currently we'll just
79581 * run through the entire input string, trivially failing the match
79582 * at every non-zero offset.
79583 */
79584
79585 if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) {
79586 DUK_DDD(DUK_DDDPRINT("match at offset %ld", (long) char_offset));
79587 match = 1;
79588 break;
79589 }
79590
79591 /* advance by one character (code point) and one char_offset */
79592 char_offset++;
79593 if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) {
79594 /*
79595 * Note:
79596 *
79597 * - Intentionally attempt (empty) match at char_offset == k_input->clen
79598 *
79599 * - Negative char_offsets have been eliminated and char_offset is duk_uint32_t
79600 * -> no need or use for a negative check
79601 */
79602
79603 DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets"));
79604 break;
79605 }
79606
79607 /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */
79608 (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1);
79609 }
79610
79611 match_over:
79612
79613 /*
79614 * Matching complete, create result array or return a 'null'. Update lastIndex
79615 * if necessary. See E5 Section 15.10.6.2.
79616 *
79617 * Because lastIndex is a character (not byte) offset, we need the character
79618 * length of the match which we conveniently get as a side effect of interning
79619 * the matching substring (0th index of result array).
79620 *
79621 * saved[0] start pointer (~ byte offset) of current match
79622 * saved[1] end pointer (~ byte offset) of current match (exclusive)
79623 * char_offset start character offset of current match (-> .index of result)
79624 * char_end_offset end character offset (computed below)
79625 */
79626
79627 /* [ ... re_obj input bc saved_buf ] */
79628
79629 if (match) {
79630#ifdef DUK_USE_ASSERTIONS
79631 duk_hobject *h_res;
79632#endif
79633 duk_uint32_t char_end_offset = 0;
79634
79635 DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld", (long) char_offset));
79636
79637 DUK_ASSERT(re_ctx.nsaved >= 2); /* must have start and end */
79638 DUK_ASSERT((re_ctx.nsaved % 2) == 0); /* and even number */
79639
79640 /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken
79641 * advantage of now. The array is not compacted either, as regexp match
79642 * objects are usually short lived.
79643 */
79644
79645 duk_push_array(ctx);
79646
79647#ifdef DUK_USE_ASSERTIONS
79648 h_res = duk_require_hobject(ctx, -1);
79649 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
79650 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
79651 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
79652#endif
79653
79654 /* [ ... re_obj input bc saved_buf res_obj ] */
79655
79656 duk_push_u32(ctx, char_offset);
79657 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INDEX);
79658
79659 duk_dup(ctx, -4);
79660 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INPUT);
79661
79662 for (i = 0; i < re_ctx.nsaved; i += 2) {
79663 /* Captures which are undefined have NULL pointers and are returned
79664 * as 'undefined'. The same is done when saved[] pointers are insane
79665 * (this should, of course, never happen in practice).
79666 */
79667 if (re_ctx.saved[i] && re_ctx.saved[i+1] && re_ctx.saved[i+1] >= re_ctx.saved[i]) {
79668 duk_hstring *h_saved;
79669
79670 duk_push_lstring(ctx,
79671 (const char *) re_ctx.saved[i],
79672 (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
79673 h_saved = duk_get_hstring(ctx, -1);
79674 DUK_ASSERT(h_saved != NULL);
79675
79676 if (i == 0) {
79677 /* Assumes that saved[0] and saved[1] are always
79678 * set by regexp bytecode (if not, char_end_offset
79679 * will be zero). Also assumes clen reflects the
79680 * correct char length.
79681 */
79682 char_end_offset = char_offset + DUK_HSTRING_GET_CHARLEN(h_saved);
79683 }
79684 } else {
79685 duk_push_undefined(ctx);
79686 }
79687
79688 /* [ ... re_obj input bc saved_buf res_obj val ] */
79689 duk_put_prop_index(ctx, -2, i / 2);
79690 }
79691
79692 /* [ ... re_obj input bc saved_buf res_obj ] */
79693
79694 /* NB: 'length' property is automatically updated by the array setup loop */
79695
79696 if (global) {
79697 /* global regexp: lastIndex updated on match */
79698 duk_push_u32(ctx, char_end_offset);
79699 duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
79700 } else {
79701 /* non-global regexp: lastIndex never updated on match */
79702 ;
79703 }
79704 } else {
79705 /*
79706 * No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless
79707 * of 'global' flag of the RegExp. In particular, if lastIndex is invalid
79708 * initially, it is reset to zero.
79709 */
79710
79711 DUK_DDD(DUK_DDDPRINT("regexp does not match"));
79712
79713 duk_push_null(ctx);
79714
79715 /* [ ... re_obj input bc saved_buf res_obj ] */
79716
79717 duk_push_int(ctx, 0);
79718 duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
79719 }
79720
79721 /* [ ... re_obj input bc saved_buf res_obj ] */
79722
79723 duk_insert(ctx, -5);
79724
79725 /* [ ... res_obj re_obj input bc saved_buf ] */
79726
79727 duk_pop_n(ctx, 4);
79728
79729 /* [ ... res_obj ] */
79730
79731 /* XXX: these last tricks are unnecessary if the function is made
79732 * a genuine native function.
79733 */
79734}
79735
79736DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) {
79737 duk__regexp_match_helper(thr, 0 /*force_global*/);
79738}
79739
79740/* This variant is needed by String.prototype.split(); it needs to perform
79741 * global-style matching on a cloned RegExp which is potentially non-global.
79742 */
79743DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
79744 duk__regexp_match_helper(thr, 1 /*force_global*/);
79745}
79746
79747#else /* DUK_USE_REGEXP_SUPPORT */
79748
79749/* regexp support disabled */
79750
79751#endif /* DUK_USE_REGEXP_SUPPORT */
79752#line 1 "duk_selftest.c"
79753/*
79754 * Self tests to ensure execution environment is sane. Intended to catch
79755 * compiler/platform problems which cannot be detected at compile time.
79756 */
79757
79758/* include removed: duk_internal.h */
79759
79760#if defined(DUK_USE_SELF_TESTS)
79761
79762/*
79763 * Unions and structs for self tests
79764 */
79765
79766typedef union {
79767 double d;
79768 duk_uint8_t c[8];
79769} duk__test_double_union;
79770
79771#define DUK__DBLUNION_CMP_TRUE(a,b) do { \
79772 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
79773 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \
79774 } \
79775 } while (0)
79776
79777#define DUK__DBLUNION_CMP_FALSE(a,b) do { \
79778 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
79779 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \
79780 } \
79781 } while (0)
79782
79783typedef union {
79784 duk_uint32_t i;
79785 duk_uint8_t c[8];
79786} duk__test_u32_union;
79787
79788/*
79789 * Various sanity checks for typing
79790 */
79791
79792DUK_LOCAL void duk__selftest_types(void) {
79793 if (!(sizeof(duk_int8_t) == 1 &&
79794 sizeof(duk_uint8_t) == 1 &&
79795 sizeof(duk_int16_t) == 2 &&
79796 sizeof(duk_uint16_t) == 2 &&
79797 sizeof(duk_int32_t) == 4 &&
79798 sizeof(duk_uint32_t) == 4)) {
79799 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int{8,16,32}_t size");
79800 }
79801#if defined(DUK_USE_64BIT_OPS)
79802 if (!(sizeof(duk_int64_t) == 8 &&
79803 sizeof(duk_uint64_t) == 8)) {
79804 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int64_t size");
79805 }
79806#endif
79807
79808 if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) {
79809 /* Some internal code now assumes that all duk_uint_t values
79810 * can be expressed with a duk_size_t.
79811 */
79812 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_size_t is smaller than duk_uint_t");
79813 }
79814 if (!(sizeof(duk_int_t) >= 4)) {
79815 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_int_t is not 32 bits");
79816 }
79817}
79818
79819/*
79820 * Packed tval sanity
79821 */
79822
79823DUK_LOCAL void duk__selftest_packed_tval(void) {
79824#if defined(DUK_USE_PACKED_TVAL)
79825 if (sizeof(void *) > 4) {
79826 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: packed duk_tval in use but sizeof(void *) > 4");
79827 }
79828#endif
79829}
79830
79831/*
79832 * Two's complement arithmetic.
79833 */
79834
79835DUK_LOCAL void duk__selftest_twos_complement(void) {
79836 volatile int test;
79837 test = -1;
79838
79839 /* Note that byte order doesn't affect this test: all bytes in
79840 * 'test' will be 0xFF for two's complement.
79841 */
79842 if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
79843 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic");
79844 }
79845}
79846
79847/*
79848 * Byte order. Important to self check, because on some exotic platforms
79849 * there is no actual detection but rather assumption based on platform
79850 * defines.
79851 */
79852
79853DUK_LOCAL void duk__selftest_byte_order(void) {
79854 duk__test_u32_union u1;
79855 duk__test_double_union u2;
79856
79857 /*
79858 * >>> struct.pack('>d', 102030405060).encode('hex')
79859 * '4237c17c6dc40000'
79860 */
79861#if defined(DUK_USE_INTEGER_LE)
79862 u1.c[0] = 0xef; u1.c[1] = 0xbe; u1.c[2] = 0xad; u1.c[3] = 0xde;
79863#elif defined(DUK_USE_INTEGER_ME)
79864#error integer mixed endian not supported now
79865#elif defined(DUK_USE_INTEGER_BE)
79866 u1.c[0] = 0xde; u1.c[1] = 0xad; u1.c[2] = 0xbe; u1.c[3] = 0xef;
79867#else
79868#error unknown integer endianness
79869#endif
79870
79871#if defined(DUK_USE_DOUBLE_LE)
79872 u2.c[0] = 0x00; u2.c[1] = 0x00; u2.c[2] = 0xc4; u2.c[3] = 0x6d;
79873 u2.c[4] = 0x7c; u2.c[5] = 0xc1; u2.c[6] = 0x37; u2.c[7] = 0x42;
79874#elif defined(DUK_USE_DOUBLE_ME)
79875 u2.c[0] = 0x7c; u2.c[1] = 0xc1; u2.c[2] = 0x37; u2.c[3] = 0x42;
79876 u2.c[4] = 0x00; u2.c[5] = 0x00; u2.c[6] = 0xc4; u2.c[7] = 0x6d;
79877#elif defined(DUK_USE_DOUBLE_BE)
79878 u2.c[0] = 0x42; u2.c[1] = 0x37; u2.c[2] = 0xc1; u2.c[3] = 0x7c;
79879 u2.c[4] = 0x6d; u2.c[5] = 0xc4; u2.c[6] = 0x00; u2.c[7] = 0x00;
79880#else
79881#error unknown double endianness
79882#endif
79883
79884 if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
79885 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_uint32_t byte order");
79886 }
79887
79888 if (u2.d != (double) 102030405060.0) {
79889 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double byte order");
79890 }
79891}
79892
79893/*
79894 * DUK_BSWAP macros
79895 */
79896
79897DUK_LOCAL void duk__selftest_bswap_macros(void) {
79898 duk_uint32_t x32;
79899 duk_uint16_t x16;
79900 duk_double_union du;
79901 duk_double_t du_diff;
79902
79903 x16 = 0xbeefUL;
79904 x16 = DUK_BSWAP16(x16);
79905 if (x16 != (duk_uint16_t) 0xefbeUL) {
79906 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP16");
79907 }
79908
79909 x32 = 0xdeadbeefUL;
79910 x32 = DUK_BSWAP32(x32);
79911 if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
79912 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP32");
79913 }
79914
79915 /* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
79916 * (2.008366013071895,)
79917 */
79918
79919 du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
79920 du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
79921 DUK_DBLUNION_DOUBLE_NTOH(&du);
79922 du_diff = du.d - 2.008366013071895;
79923#if 0
79924 DUK_FPRINTF(DUK_STDERR, "du_diff: %lg\n", (double) du_diff);
79925#endif
79926 if (du_diff > 1e-15) {
79927 /* Allow very small lenience because some compilers won't parse
79928 * exact IEEE double constants (happened in matrix testing with
79929 * Linux gcc-4.8 -m32 at least).
79930 */
79931#if 0
79932 DUK_FPRINTF(DUK_STDERR, "Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
79933 (unsigned int) du.uc[0], (unsigned int) du.uc[1],
79934 (unsigned int) du.uc[2], (unsigned int) du.uc[3],
79935 (unsigned int) du.uc[4], (unsigned int) du.uc[5],
79936 (unsigned int) du.uc[6], (unsigned int) du.uc[7]);
79937#endif
79938 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_DBLUNION_DOUBLE_NTOH");
79939 }
79940}
79941
79942/*
79943 * Basic double / byte union memory layout.
79944 */
79945
79946DUK_LOCAL void duk__selftest_double_union_size(void) {
79947 if (sizeof(duk__test_double_union) != 8) {
79948 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: invalid union size");
79949 }
79950}
79951
79952/*
79953 * Union aliasing, see misc/clang_aliasing.c.
79954 */
79955
79956DUK_LOCAL void duk__selftest_double_aliasing(void) {
79957 duk__test_double_union a, b;
79958
79959 /* This testcase fails when Emscripten-generated code runs on Firefox.
79960 * It's not an issue because the failure should only affect packed
79961 * duk_tval representation, which is not used with Emscripten.
79962 */
79963#if !defined(DUK_USE_PACKED_TVAL)
79964 DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
79965 return;
79966#endif
79967
79968 /* Test signaling NaN and alias assignment in all endianness combinations.
79969 */
79970
79971 /* little endian */
79972 a.c[0] = 0x11; a.c[1] = 0x22; a.c[2] = 0x33; a.c[3] = 0x44;
79973 a.c[4] = 0x00; a.c[5] = 0x00; a.c[6] = 0xf1; a.c[7] = 0xff;
79974 b = a;
79975 DUK__DBLUNION_CMP_TRUE(&a, &b);
79976
79977 /* big endian */
79978 a.c[0] = 0xff; a.c[1] = 0xf1; a.c[2] = 0x00; a.c[3] = 0x00;
79979 a.c[4] = 0x44; a.c[5] = 0x33; a.c[6] = 0x22; a.c[7] = 0x11;
79980 b = a;
79981 DUK__DBLUNION_CMP_TRUE(&a, &b);
79982
79983 /* mixed endian */
79984 a.c[0] = 0x00; a.c[1] = 0x00; a.c[2] = 0xf1; a.c[3] = 0xff;
79985 a.c[4] = 0x11; a.c[5] = 0x22; a.c[6] = 0x33; a.c[7] = 0x44;
79986 b = a;
79987 DUK__DBLUNION_CMP_TRUE(&a, &b);
79988}
79989
79990/*
79991 * Zero sign, see misc/tcc_zerosign2.c.
79992 */
79993
79994DUK_LOCAL void duk__selftest_double_zero_sign(void) {
79995 duk__test_double_union a, b;
79996
79997 a.d = 0.0;
79998 b.d = -a.d;
79999 DUK__DBLUNION_CMP_FALSE(&a, &b);
80000}
80001
80002/*
80003 * Struct size/alignment if platform requires it
80004 *
80005 * There are some compiler specific struct padding pragmas etc in use, this
80006 * selftest ensures they're correctly detected and used.
80007 */
80008
80009DUK_LOCAL void duk__selftest_struct_align(void) {
80010#if (DUK_USE_ALIGN_BY == 4)
80011 if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
80012 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 4");
80013 }
80014#elif (DUK_USE_ALIGN_BY == 8)
80015 if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
80016 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 8");
80017 }
80018#elif (DUK_USE_ALIGN_BY == 1)
80019 /* no check */
80020#else
80021#error invalid DUK_USE_ALIGN_BY
80022#endif
80023}
80024
80025/*
80026 * 64-bit arithmetic
80027 *
80028 * There are some platforms/compilers where 64-bit types are available
80029 * but don't work correctly. Test for known cases.
80030 */
80031
80032DUK_LOCAL void duk__selftest_64bit_arithmetic(void) {
80033#if defined(DUK_USE_64BIT_OPS)
80034 volatile duk_int64_t i;
80035 volatile duk_double_t d;
80036
80037 /* Catch a double-to-int64 cast issue encountered in practice. */
80038 d = 2147483648.0;
80039 i = (duk_int64_t) d;
80040 if (i != 0x80000000LL) {
80041 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: casting 2147483648.0 to duk_int64_t failed");
80042 }
80043#else
80044 /* nop */
80045#endif
80046}
80047
80048/*
80049 * Casting
80050 */
80051
80052DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) {
80053 /*
80054 * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
80055 */
80056
80057 duk_double_t d1, d2;
80058 duk_small_uint_t u;
80059
80060 duk_double_t d1v, d2v;
80061 duk_small_uint_t uv;
80062
80063 /* Test without volatiles */
80064
80065 d1 = 1.0;
80066 u = (duk_small_uint_t) d1;
80067 d2 = (duk_double_t) u;
80068
80069 if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) {
80070 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
80071 }
80072
80073 /* Same test with volatiles */
80074
80075 d1v = 1.0;
80076 uv = (duk_small_uint_t) d1v;
80077 d2v = (duk_double_t) uv;
80078
80079 if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) {
80080 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
80081 }
80082}
80083
80084DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) {
80085 /*
80086 * This test fails on an exotic ARM target; double-to-uint
80087 * cast is incorrectly clamped to -signed- int highest value.
80088 *
80089 * https://github.com/svaarala/duktape/issues/336
80090 */
80091
80092 duk_double_t dv;
80093 duk_uint32_t uv;
80094
80095 dv = 3735928559.0; /* 0xdeadbeef in decimal */
80096 uv = (duk_uint32_t) dv;
80097
80098 if (uv != 0xdeadbeefUL) {
80099 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_uint32_t cast failed");
80100 }
80101}
80102
80103/*
80104 * Self test main
80105 */
80106
80107DUK_INTERNAL void duk_selftest_run_tests(void) {
80108 duk__selftest_types();
80109 duk__selftest_packed_tval();
80110 duk__selftest_twos_complement();
80111 duk__selftest_byte_order();
80112 duk__selftest_bswap_macros();
80113 duk__selftest_double_union_size();
80114 duk__selftest_double_aliasing();
80115 duk__selftest_double_zero_sign();
80116 duk__selftest_struct_align();
80117 duk__selftest_64bit_arithmetic();
80118 duk__selftest_cast_double_to_small_uint();
80119 duk__selftest_cast_double_to_uint32();
80120}
80121
80122#undef DUK__DBLUNION_CMP_TRUE
80123#undef DUK__DBLUNION_CMP_FALSE
80124
80125#endif /* DUK_USE_SELF_TESTS */
80126/* include removed: duk_internal.h */
80127#line 2 "duk_tval.c"
80128
80129#if defined(DUK_USE_FASTINT)
80130
80131/*
80132 * Manually optimized double-to-fastint downgrade check.
80133 *
80134 * This check has a large impact on performance, especially for fastint
80135 * slow paths, so must be changed carefully. The code should probably be
80136 * optimized for the case where the result does not fit into a fastint,
80137 * to minimize the penalty for "slow path code" dealing with fractions etc.
80138 *
80139 * At least on one tested soft float ARM platform double-to-int64 coercion
80140 * is very slow (and sometimes produces incorrect results, see self tests).
80141 * This algorithm combines a fastint compatibility check and extracting the
80142 * integer value from an IEEE double for setting the tagged fastint. For
80143 * other platforms a more naive approach might be better.
80144 *
80145 * See doc/fastint.rst for details.
80146 */
80147
80148DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) {
80149 duk_double_union du;
80150 duk_int64_t i;
80151 duk_small_int_t expt;
80152 duk_small_int_t shift;
80153
80154 /* XXX: optimize for packed duk_tval directly? */
80155
80156 du.d = x;
80157 i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du);
80158 expt = (duk_small_int_t) ((i >> 52) & 0x07ff);
80159 shift = expt - 1023;
80160
80161 if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
80162 duk_int64_t t;
80163
80164 if (((0x000fffffffffffffLL >> shift) & i) == 0) {
80165 t = i | 0x0010000000000000LL; /* implicit leading one */
80166 t = t & 0x001fffffffffffffLL;
80167 t = t >> (52 - shift);
80168 if (i < 0) {
80169 t = -t;
80170 }
80171 DUK_TVAL_SET_FASTINT(tv, t);
80172 return;
80173 }
80174 } else if (shift == -1023) { /* exponent 0 */
80175 if (i >= 0 && (i & 0x000fffffffffffffLL) == 0) {
80176 /* Note: reject negative zero. */
80177 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
80178 return;
80179 }
80180 } else if (shift == 47) { /* exponent 1070 */
80181 if (i < 0 && (i & 0x000fffffffffffffLL) == 0) {
80182 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
80183 return;
80184 }
80185 }
80186
80187 DUK_TVAL_SET_DOUBLE(tv, x);
80188 return;
80189}
80190
80191/*
80192 * Manually optimized number-to-double conversion
80193 */
80194
80195#if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL)
80196DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) {
80197 duk_double_union du;
80198 duk_uint64_t t;
80199
80200 t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
80201 if ((t >> 48) != DUK_TAG_FASTINT) {
80202 return tv->d;
80203 } else if (t & 0x0000800000000000ULL) {
80204 t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
80205 t = t & 0x0000ffffffffffffULL; /* negative */
80206 t |= 0xc330000000000000ULL;
80207 DUK_DBLUNION_SET_UINT64(&du, t);
80208 return du.d + 4503599627370496.0; /* 1 << 52 */
80209 } else if (t != 0) {
80210 t &= 0x0000ffffffffffffULL; /* positive */
80211 t |= 0x4330000000000000ULL;
80212 DUK_DBLUNION_SET_UINT64(&du, t);
80213 return du.d - 4503599627370496.0; /* 1 << 52 */
80214 } else {
80215 return 0.0; /* zero */
80216 }
80217}
80218#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
80219
80220#if 0 /* unused */
80221#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
80222DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) {
80223 duk_double_union du;
80224 duk_uint64_t t;
80225
80226 DUK_ASSERT(tv->t == DUK__TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
80227
80228 if (tv->t == DUK_TAG_FASTINT) {
80229 if (tv->v.fi >= 0) {
80230 t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
80231 DUK_DBLUNION_SET_UINT64(&du, t);
80232 return du.d - 4503599627370496.0; /* 1 << 52 */
80233 } else {
80234 t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
80235 DUK_DBLUNION_SET_UINT64(&du, t);
80236 return du.d + 4503599627370496.0; /* 1 << 52 */
80237 }
80238 } else {
80239 return tv->v.d;
80240 }
80241}
80242#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
80243#endif /* 0 */
80244
80245#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
80246DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) {
80247 duk_double_union du;
80248 duk_uint64_t t;
80249
80250 DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
80251
80252 if (tv->v.fi >= 0) {
80253 t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
80254 DUK_DBLUNION_SET_UINT64(&du, t);
80255 return du.d - 4503599627370496.0; /* 1 << 52 */
80256 } else {
80257 t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
80258 DUK_DBLUNION_SET_UINT64(&du, t);
80259 return du.d + 4503599627370496.0; /* 1 << 52 */
80260 }
80261}
80262#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
80263
80264#endif /* DUK_USE_FASTINT */
80265#line 1 "duk_unicode_tables.c"
80266/*
80267 * Unicode support tables automatically generated during build.
80268 */
80269
80270/* include removed: duk_internal.h */
80271
80272/*
80273 * Unicode tables containing ranges of Unicode characters in a
80274 * packed format. These tables are used to match non-ASCII
80275 * characters of complex productions by resorting to a linear
80276 * range-by-range comparison. This is very slow, but is expected
80277 * to be very rare in practical Ecmascript source code, and thus
80278 * compactness is most important.
80279 *
80280 * The tables are matched using uni_range_match() and the format
80281 * is described in src/extract_chars.py.
80282 */
80283
80284#ifdef DUK_USE_SOURCE_NONBMP
80285/* IdentifierStart production with ASCII excluded */
80286/* duk_unicode_ids_noa[] */
80287/*
80288 * Automatically generated by extract_chars.py, do not edit!
80289 */
80290
80291const duk_uint8_t duk_unicode_ids_noa[791] = {
80292249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
80293240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
8029418,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
80295101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
8029652,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
80297240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
802982,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
80299114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
80300240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
8030126,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
80302205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
8030335,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
80304180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
80305146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
8030679,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
80307251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
8030892,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
80309240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
80310122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
8031174,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
80312255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
8031347,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
8031434,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
80315240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
80316240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
8031724,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
80318171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,241,91,47,10,47,3,
8031933,46,61,241,79,107,243,127,37,255,223,13,79,33,242,31,15,240,63,11,242,
80320127,14,63,20,87,36,241,207,142,255,226,86,83,2,241,194,20,3,240,127,156,
80321240,107,240,175,184,15,1,50,34,240,191,30,240,223,117,242,107,240,107,240,
8032263,127,243,159,254,42,239,37,243,223,29,255,238,68,255,226,97,248,63,83,
80323255,234,145,255,227,33,255,240,2,44,95,254,18,191,255,0,52,187,31,255,0,18,
80324242,244,82,243,114,19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,98,
80325255,224,70,63,9,47,9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,
80326240,1,114,143,255,0,149,201,241,191,254,242,124,252,239,255,0,46,214,255,
80327225,16,0,
80328};
80329#else
80330/* IdentifierStart production with ASCII and non-BMP excluded */
80331/* duk_unicode_ids_noabmp[] */
80332/*
80333 * Automatically generated by extract_chars.py, do not edit!
80334 */
80335
80336const duk_uint8_t duk_unicode_ids_noabmp[611] = {
80337249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
80338240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
8033918,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
80340101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
8034152,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
80342240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
803432,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
80344114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
80345240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
8034626,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
80347205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
8034835,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
80349180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
80350146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
8035179,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
80352251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
8035392,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
80354240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
80355122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
8035674,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
80357255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
8035847,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
8035934,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
80360240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
80361240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
8036224,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
80363171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,0,
80364};
80365#endif
80366
80367#ifdef DUK_USE_SOURCE_NONBMP
80368/* IdentifierStart production with Letter and ASCII excluded */
80369/* duk_unicode_ids_m_let_noa[] */
80370/*
80371 * Automatically generated by extract_chars.py, do not edit!
80372 */
80373
80374const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
80375255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
80376249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,48,
80377};
80378#else
80379/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
80380/* duk_unicode_ids_m_let_noabmp[] */
80381/*
80382 * Automatically generated by extract_chars.py, do not edit!
80383 */
80384
80385const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
80386255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
80387249,0,
80388};
80389#endif
80390
80391#ifdef DUK_USE_SOURCE_NONBMP
80392/* IdentifierPart production with IdentifierStart and ASCII excluded */
80393/* duk_unicode_idp_m_ids_noa[] */
80394/*
80395 * Automatically generated by extract_chars.py, do not edit!
80396 */
80397
80398const duk_uint8_t duk_unicode_idp_m_ids_noa[397] = {
80399255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
80400245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
8040136,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
8040257,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
80403240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
80404242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
8040534,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
8040653,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
80407211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
8040879,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
80409185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
804104,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
80411109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
80412121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
80413240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
8041496,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
80415240,162,251,41,241,112,255,225,177,15,254,25,105,255,228,75,34,22,63,26,37,
8041615,254,75,66,242,126,241,25,240,34,241,250,255,240,10,249,228,69,151,54,
80417241,3,248,98,255,228,125,242,47,255,12,23,244,254,0,
80418};
80419#else
80420/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
80421/* duk_unicode_idp_m_ids_noabmp[] */
80422/*
80423 * Automatically generated by extract_chars.py, do not edit!
80424 */
80425
80426const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348] = {
80427255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
80428245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
8042936,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
8043057,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
80431240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
80432242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
8043334,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
8043453,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
80435211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
8043679,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
80437185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
804384,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
80439109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
80440121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
80441240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
8044296,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
80443240,162,251,41,241,112,0,
80444};
80445#endif
80446
80447/*
80448 * Case conversion tables generated using src/extract_caseconv.py.
80449 */
80450
80451/* duk_unicode_caseconv_uc[] */
80452/* duk_unicode_caseconv_lc[] */
80453
80454/*
80455 * Automatically generated by extract_caseconv.py, do not edit!
80456 */
80457
80458const duk_uint8_t duk_unicode_caseconv_uc[1288] = {
80459132,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
80460128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
80461104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,15,128,15,132,8,31,16,
8046231,24,12,62,64,62,80,32,124,192,124,224,64,250,0,250,64,97,246,1,246,129,3,
80463238,3,247,64,135,220,135,242,2,15,187,15,237,2,31,120,31,248,4,62,244,63,
80464212,8,125,240,127,232,16,253,128,253,192,33,253,1,253,128,67,252,3,253,0,
80465136,92,8,88,8,18,104,18,91,26,44,48,44,0,94,90,0,33,64,155,253,7,252,132,
80466212,0,32,32,32,6,0,76,192,76,129,128,157,0,156,136,1,75,1,74,46,2,244,2,
80467242,12,6,12,6,8,16,13,8,13,0,48,27,64,27,48,64,57,192,57,162,0,119,192,119,
80468132,128,252,128,252,20,2,35,2,34,18,4,142,4,140,20,13,196,13,192,16,30,200,
8046930,192,192,70,16,70,2,32,145,96,145,70,193,48,129,48,67,130,104,130,104,44,
8047030,1,30,0,150,61,66,61,64,192,125,68,125,100,33,99,65,99,56,50,200,18,200,
804716,69,157,133,157,96,169,144,105,144,11,211,64,211,64,12,167,35,167,34,15,
8047278,103,78,100,126,157,234,157,228,21,59,253,59,240,90,122,26,122,0,163,128,
80473214,128,214,2,1,197,1,196,6,3,140,3,136,12,7,200,7,196,16,20,0,13,48,32,63,
80474128,63,112,69,142,101,142,64,130,1,136,1,135,4,3,114,3,112,8,26,120,202,
80475120,176,65,1,30,1,29,130,2,105,1,150,5,255,96,22,160,115,128,31,224,47,0,
8047638,32,9,32,47,224,10,96,48,0,72,96,50,64,50,32,50,160,62,192,51,32,51,0,51,
8047764,71,160,51,192,68,0,53,0,52,224,55,224,62,224,59,160,49,192,62,96,62,32,
8047874,5,141,224,74,37,141,160,74,69,142,0,74,96,48,32,74,128,48,192,75,32,49,
80479224,75,96,50,0,76,0,50,96,76,96,50,128,76,180,241,160,77,0,50,224,77,101,
80480140,64,78,37,141,192,78,64,51,160,78,160,51,224,79,165,140,128,81,0,53,192,
8048181,32,72,128,81,128,72,160,82,64,54,224,104,160,115,32,110,224,110,192,117,
80482128,112,192,120,64,116,96,121,128,113,128,122,0,114,64,122,32,115,0,122,
80483160,116,192,122,192,116,0,122,224,121,224,126,0,115,64,126,32,116,32,126,
8048464,127,32,126,160,114,160,153,224,152,3,175,52,239,163,175,165,140,99,211,
8048599,204,3,247,192,115,35,252,163,253,132,41,196,38,68,48,132,48,101,140,37,
80486140,5,140,160,71,69,140,192,71,217,128,55,224,5,48,5,48,20,152,10,240,1,56,
804877,194,0,74,3,12,3,144,192,230,64,194,0,192,64,236,48,58,80,48,128,48,16,88,
80488120,20,212,21,72,122,90,0,72,3,49,30,151,128,21,0,194,7,166,32,5,112,48,
80489161,233,152,1,100,12,40,122,106,0,65,2,190,31,80,128,233,64,196,199,212,
80490176,58,80,49,48,48,1,245,76,14,148,12,76,12,4,125,91,3,165,3,19,3,66,31,
80491128,135,194,0,230,71,224,97,240,144,57,145,248,40,124,40,14,100,126,14,31,
8049211,3,153,31,132,135,195,0,230,71,225,97,240,208,57,145,248,104,124,56,14,
80493100,126,30,31,15,3,153,31,136,135,194,0,230,71,226,97,240,144,57,145,248,
80494168,124,40,14,100,126,46,31,11,3,153,31,140,135,195,0,230,71,227,97,240,
80495208,57,145,248,232,124,56,14,100,126,62,31,15,3,153,31,144,135,202,0,230,
8049671,228,97,242,144,57,145,249,40,124,168,14,100,126,78,31,43,3,153,31,148,
80497135,203,0,230,71,229,97,242,208,57,145,249,104,124,184,14,100,126,94,31,47,
804983,153,31,152,135,202,0,230,71,230,97,242,144,57,145,249,168,124,168,14,100,
80499126,110,31,43,3,153,31,156,135,203,0,230,71,231,97,242,208,57,145,249,232,
80500124,184,14,100,126,126,31,47,3,153,31,160,135,218,0,230,71,232,97,246,144,
8050157,145,250,40,125,168,14,100,126,142,31,107,3,153,31,164,135,219,0,230,71,
80502233,97,246,208,57,145,250,104,125,184,14,100,126,158,31,111,3,153,31,168,
80503135,218,0,230,71,234,97,246,144,57,145,250,168,125,168,14,100,126,174,31,
80504107,3,153,31,172,135,219,0,230,71,235,97,246,208,57,145,250,232,125,184,14,
80505100,126,190,31,111,3,153,31,178,135,238,128,230,71,236,224,57,16,57,145,
80506251,72,14,24,14,100,126,218,3,145,3,66,31,183,192,228,64,208,128,230,71,
80507239,32,57,16,57,145,252,40,127,40,14,100,127,14,3,151,3,153,31,196,128,226,
8050864,230,71,241,160,57,112,52,33,252,124,14,92,13,8,14,100,127,50,3,151,3,
80509153,31,210,192,230,64,194,0,192,7,244,240,57,144,48,128,48,17,253,104,14,
80510100,13,8,127,95,3,153,3,8,3,66,31,226,192,233,64,194,0,192,7,248,240,58,80,
8051148,128,48,17,254,72,14,132,12,76,127,154,3,165,3,66,31,231,192,233,64,194,
805120,208,135,252,161,255,160,57,145,255,56,14,164,14,100,127,210,3,143,3,153,
8051331,246,128,234,64,208,135,253,240,58,144,52,32,57,145,255,200,14,164,14,
80514103,236,2,0,70,0,70,251,1,128,17,128,18,126,192,160,4,96,4,207,176,60,1,24,
805151,24,1,39,236,19,0,70,0,70,0,76,251,5,128,20,192,21,62,193,160,5,48,5,79,
80516177,56,21,16,21,27,236,82,5,68,5,53,251,21,129,81,1,78,254,197,160,84,224,
8051784,111,177,120,21,16,20,244,
80518};
80519const duk_uint8_t duk_unicode_caseconv_lc[616] = {
80520144,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
80521235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
805220,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,15,132,15,128,8,31,24,
8052331,16,12,62,80,62,64,32,124,224,124,192,64,250,64,250,0,97,246,129,246,1,3,
80524241,3,240,2,7,230,7,228,4,15,212,15,208,8,31,184,31,176,4,63,116,62,224,8,
80525127,32,125,200,32,254,192,254,128,33,253,161,247,96,67,253,3,252,0,135,250,
80526135,222,129,15,252,15,188,2,31,250,31,124,4,66,192,66,224,64,146,216,147,
8052764,209,96,1,97,130,242,199,224,35,240,95,228,63,232,38,161,1,0,1,1,48,2,
80528100,2,102,12,4,228,4,232,64,10,80,10,89,112,23,144,23,160,96,48,64,48,96,
80529128,104,0,104,65,128,217,128,218,2,1,203,1,204,18,3,188,3,190,36,7,200,7,
80530204,16,15,192,15,201,64,34,32,34,49,32,72,192,72,225,64,220,0,220,65,1,236,
805311,236,140,4,96,4,97,34,9,20,9,22,108,19,4,19,8,56,38,128,38,138,193,224,1,
80532224,25,99,212,3,212,44,7,214,71,212,66,22,51,150,52,3,44,128,44,129,100,89,
80533214,89,216,10,153,2,153,4,189,52,5,52,8,202,114,42,114,48,244,230,84,230,
80534103,233,222,105,222,129,83,191,83,191,133,167,160,167,161,10,48,13,48,20,0,
8053532,26,192,26,208,64,56,128,56,192,192,113,64,113,129,1,251,129,252,2,44,
80536114,44,115,4,16,12,56,12,64,32,27,128,27,144,64,211,197,211,198,2,8,6,88,9,
80537164,16,17,216,17,224,47,245,1,120,0,255,1,129,2,83,1,134,2,84,1,142,1,221,
805381,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,
805391,153,1,157,2,114,1,159,2,117,1,167,1,168,1,174,2,136,1,183,2,146,1,241,1,
80540243,1,246,1,149,1,247,1,191,2,32,1,158,2,58,44,101,2,61,1,154,2,62,44,102,
805412,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,
805423,215,3,244,3,184,3,249,3,242,4,192,4,207,30,158,0,223,31,188,31,179,31,
80543204,31,195,31,236,31,229,31,252,31,243,33,38,3,201,33,42,0,107,33,43,0,229,
8054433,50,33,78,33,131,33,132,44,96,44,97,44,98,2,107,44,99,29,125,44,100,2,
80545125,44,109,2,81,44,110,2,113,44,111,2,80,44,112,2,82,167,125,29,121,167,
80546141,2,101,2,2,97,0,52,129,131,128,
80547};
80548
80549#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
80550/*
80551 * Automatically generated by extract_caseconv.py, do not edit!
80552 */
80553
80554const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
805550,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,
8055628,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
8055753,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,
8055878,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70,
8055971,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,123,124,125,
80560126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
80561144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
80562162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
80563180,924,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
80564198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
80565216,217,218,219,220,221,222,223,192,193,194,195,196,197,198,199,200,201,
80566202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219,
80567220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268,
80568270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286,
80569288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305,
80570306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323,
80571323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340,
80572342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358,
80573360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377,
80574377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395,
80575395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413,
80576544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431,
80577431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449,
80578450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467,
80579467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484,
80580486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503,
80581504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520,
80582522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538,
80583540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556,
80584558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390,
8058511391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375,
8058611373,11376,385,390,597,393,394,600,399,602,400,604,605,606,607,403,609,
80587610,404,612,42893L,614,615,407,406,618,11362,620,621,622,412,624,11374,413,
80588627,628,415,630,631,632,633,634,635,636,11364,638,639,422,641,642,425,644,
80589645,646,647,430,580,433,434,581,653,654,655,656,657,439,659,660,661,662,
80590663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,
80591681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,
80592699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,
80593717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,
80594735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,
80595753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,
80596771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,
80597789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,
80598807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,
80599825,826,827,828,829,830,831,832,833,834,835,836,921,838,839,840,841,842,
80600843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,
80601861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,
80602879,880,880,882,882,884,885,886,886,888,889,890,1021,1022,1023,894,895,896,
80603897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,
80604915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,
80605933,934,935,936,937,938,939,902,904,905,906,944,913,914,915,916,917,918,
80606919,920,921,922,923,924,925,926,927,928,929,931,931,932,933,934,935,936,
80607937,938,939,908,910,911,975,914,920,978,979,980,934,928,975,984,984,986,
80608986,988,988,990,990,992,992,994,994,996,996,998,998,1000,1000,1002,1002,
806091004,1004,1006,1006,922,929,1017,1011,1012,917,1014,1015,1015,1017,1018,
806101018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,
806111034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,
806121049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,
806131064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042,1043,1044,1045,1046,
806141047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,
806151062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,1025,1026,1027,1028,
806161029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1120,1120,1122,1122,
806171124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134,1134,1136,1136,1138,
806181138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148,1150,1150,1152,1152,
806191154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164,1164,1166,1166,1168,
806201168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178,1180,1180,1182,1182,
806211184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194,1194,1196,1196,1198,
806221198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208,1210,1210,1212,1212,
806231214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223,1225,1225,1227,1227,
806241229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238,1240,1240,1242,1242,
806251244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254,1254,1256,1256,1258,
806261258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268,1270,1270,1272,1272,
806271274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284,1284,1286,1286,1288,
806281288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298,1300,1300,1302,1302,
806291304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314,1314,1316,1316,1318,
806301318,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,
806311334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,
806321349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,
806331364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1329,1330,
806341331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,
806351346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,
806361361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419,1420,1421,1422,1423,
806371424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,
806381439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,
806391454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,
806401469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,
806411484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,
806421499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,
806431514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,
806441529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,
806451544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,
806461559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,
806471574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,
806481589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,
806491604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,
806501619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,
806511634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,
806521649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,
806531664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,
806541679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,
806551694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,
806561709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,
806571724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,
806581739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,
806591754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,
806601769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,
806611784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,
806621799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,
806631814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,
806641829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,
806651844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,
806661859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,
806671874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,
806681889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,
806691904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,
806701919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,
806711934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,
806721949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,
806731964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,
806741979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,
806751994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,
806762009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,
806772024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,
806782039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,
806792054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,
806802069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,
806812084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,
806822099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,
806832114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,
806842129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,
806852144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,
806862159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,
806872174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,
806882189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,
806892204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,
806902219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,
806912234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,
806922249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,
806932264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,
806942279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,
806952294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,
806962309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,
806972324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,
806982339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,
806992354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,
807002369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,
807012384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,
807022399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,
807032414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,
807042429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,
807052444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,
807062459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,
807072474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,
807082489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,
807092504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,
807102519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,
807112534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,
807122549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,
807132564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,
807142579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,
807152594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,
807162609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,
807172624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,
807182639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,
807192654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,
807202669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,
807212684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,
807222699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,
807232714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,
807242729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,
807252744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,
807262759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,
807272774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,
807282789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,
807292804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,
807302819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,
807312834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,
807322849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,
807332864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,
807342879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,
807352894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,
807362909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,
807372924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,
807382939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,
807392954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,
807402969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,
807412984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,
807422999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,
807433014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,
807443029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,
807453044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,
807463059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,
807473074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,
807483089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,
807493104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,
807503119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,
807513134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,
807523149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,
807533164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,
807543179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,
807553194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,
807563209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,
807573224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,
807583239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,
807593254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,
807603269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,
807613284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,
807623299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,
807633314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,
807643329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,
807653344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,
807663359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,
807673374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,
807683389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,
807693404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,
807703419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,
807713434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,
807723449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,
807733464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,
807743479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,
807753494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,
807763509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,
807773524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,
807783539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,
807793554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,
807803569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,
807813584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,
807823599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,
807833614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,
807843629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,
807853644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,
807863659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,
807873674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,
807883689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,
807893704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,
807903719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,
807913734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,
807923749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,
807933764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,
807943779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,
807953794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,
807963809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,
807973824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,
807983839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,
807993854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,
808003869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,
808013884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,
808023899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,
808033914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,
808043929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,
808053944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,
808063959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,
808073974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,
808083989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,
808094004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,
808104019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,
808114034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,
808124049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,
808134064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,
808144079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,
808154094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,
808164109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,
808174124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,
808184139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,
808194154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,
808204169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,
808214184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,
808224199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,
808234214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,
808244229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,
808254244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,
808264259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,
808274274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,
808284289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,
808294304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,
808304319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,
808314334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,
808324349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,
808334364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,
808344379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,
808354394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,
808364409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,
808374424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,
808384439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,
808394454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,
808404469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,
808414484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,
808424499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,
808434514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,
808444529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,
808454544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,
808464559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,
808474574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,
808484589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,
808494604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,
808504619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,
808514634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,
808524649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,
808534664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,
808544679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,
808554694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,
808564709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,
808574724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,
808584739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,
808594754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,
808604769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,
808614784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,
808624799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,
808634814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,
808644829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,
808654844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,
808664859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,
808674874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,
808684889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,
808694904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,
808704919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,
808714934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,
808724949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,
808734964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,
808744979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,
808754994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,
808765009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,
808775024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,
808785039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,
808795054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,
808805069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,
808815084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,
808825099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,5113,
808835114,5115,5116,5117,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,
808845129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,
808855144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,5155,5156,5157,5158,
808865159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,
808875174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,
808885189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,
808895204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,5215,5216,5217,5218,
808905219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,
808915234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,
808925249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,
808935264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,
808945279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,
808955294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,
808965309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5323,
808975324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,5335,5336,5337,5338,
808985339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,
808995354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,
809005369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,
809015384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,
809025399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,5413,
809035414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,
809045429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440,5441,5442,5443,
809055444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,
809065459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,
809075474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,
809085489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,
809095504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,
809105519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,
809115534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,
809125549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,
809135564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,
809145579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,5590,5591,5592,5593,
809155594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,
809165609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,
809175624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,
809185639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,5650,5651,5652,5653,
809195654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,5665,5666,5667,5668,
809205669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680,5681,5682,5683,
809215684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,
809225699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712,5713,
809235714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728,
809245729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,
809255744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,
809265759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,
809275774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,
809285789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,
809295804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,
809305819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831,5832,5833,
809315834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847,5848,
809325849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860,5861,5862,5863,
809335864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876,5877,5878,
809345879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892,5893,
809355894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905,5906,5907,5908,
809365909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920,5921,5922,5923,
809375924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5938,
809385939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952,5953,
809395954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,
809405969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,
809415984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,
809425999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,
809436014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,
809446029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,
809456044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,
809466059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071,6072,6073,
809476074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,
809486089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102,6103,
809496104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118,
809506119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132,6133,
809516134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148,
809526149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,
809536164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,
809546179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,
809556194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,
809566209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,
809576224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,
809586239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,
809596254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,6265,6266,6267,6268,
809606269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,
809616284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,
809626299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,6310,6311,6312,6313,
809636314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,
809646329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,6340,6341,6342,6343,
809656344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,
809666359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,
809676374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,6385,6386,6387,6388,
809686389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,6400,6401,6402,6403,
809696404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,6415,6416,6417,6418,
809706419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,6430,6431,6432,6433,
809716434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444,6445,6446,6447,6448,
809726449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6460,6461,6462,6463,
809736464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474,6475,6476,6477,6478,
809746479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,
809756494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,6508,
809766509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,6520,6521,6522,6523,
809776524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,6535,6536,6537,6538,
809786539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,
809796554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565,6566,6567,6568,
809806569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581,6582,6583,
809816584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,
809826599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613,
809836614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,
809846629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639,6640,6641,6642,6643,
809856644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,6655,6656,6657,6658,
809866659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,
809876674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,
809886689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,
809896704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,
809906719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731,6732,6733,
809916734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,6745,6746,6747,6748,
809926749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,
809936764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,
809946779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,
809956794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,
809966809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,6820,6821,6822,6823,
809976824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,6835,6836,6837,6838,
809986839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,
809996854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,
810006869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,
810016884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,6895,6896,6897,6898,
810026899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,6910,6911,6912,6913,
810036914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,
810046929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,
810056944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,
810066959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,
810076974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,6985,6986,6987,6988,
810086989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,7000,7001,7002,7003,
810097004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,7015,7016,7017,7018,
810107019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,7030,7031,7032,7033,
810117034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044,7045,7046,7047,7048,
810127049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,7060,7061,7062,7063,
810137064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,7075,7076,7077,7078,
810147079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,7090,7091,7092,7093,
810157094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105,7106,7107,7108,
810167109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122,7123,
810177124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138,
810187139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,
810197154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,
810207169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,
810217184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,
810227199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,
810237214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,
810247229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,
810257244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,
810267259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,
810277274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,
810287289,7290,7291,7292,7293,7294,7295,7296,7297,7298,7299,7300,7301,7302,7303,
810297304,7305,7306,7307,7308,7309,7310,7311,7312,7313,7314,7315,7316,7317,7318,
810307319,7320,7321,7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,
810317334,7335,7336,7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,
810327349,7350,7351,7352,7353,7354,7355,7356,7357,7358,7359,7360,7361,7362,7363,
810337364,7365,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375,7376,7377,7378,
810347379,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,
810357394,7395,7396,7397,7398,7399,7400,7401,7402,7403,7404,7405,7406,7407,7408,
810367409,7410,7411,7412,7413,7414,7415,7416,7417,7418,7419,7420,7421,7422,7423,
810377424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,
810387439,7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,
810397454,7455,7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,
810407469,7470,7471,7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,
810417484,7485,7486,7487,7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,
810427499,7500,7501,7502,7503,7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,
810437514,7515,7516,7517,7518,7519,7520,7521,7522,7523,7524,7525,7526,7527,7528,
810447529,7530,7531,7532,7533,7534,7535,7536,7537,7538,7539,7540,7541,7542,7543,
810457544,42877L,7546,7547,7548,11363,7550,7551,7552,7553,7554,7555,7556,7557,
810467558,7559,7560,7561,7562,7563,7564,7565,7566,7567,7568,7569,7570,7571,7572,
810477573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583,7584,7585,7586,7587,
810487588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599,7600,7601,7602,
810497603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615,7616,7617,
810507618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,
810517633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,
810527648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,
810537663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7674,7675,7676,7677,
810547678,7679,7680,7680,7682,7682,7684,7684,7686,7686,7688,7688,7690,7690,7692,
810557692,7694,7694,7696,7696,7698,7698,7700,7700,7702,7702,7704,7704,7706,7706,
810567708,7708,7710,7710,7712,7712,7714,7714,7716,7716,7718,7718,7720,7720,7722,
810577722,7724,7724,7726,7726,7728,7728,7730,7730,7732,7732,7734,7734,7736,7736,
810587738,7738,7740,7740,7742,7742,7744,7744,7746,7746,7748,7748,7750,7750,7752,
810597752,7754,7754,7756,7756,7758,7758,7760,7760,7762,7762,7764,7764,7766,7766,
810607768,7768,7770,7770,7772,7772,7774,7774,7776,7776,7778,7778,7780,7780,7782,
810617782,7784,7784,7786,7786,7788,7788,7790,7790,7792,7792,7794,7794,7796,7796,
810627798,7798,7800,7800,7802,7802,7804,7804,7806,7806,7808,7808,7810,7810,7812,
810637812,7814,7814,7816,7816,7818,7818,7820,7820,7822,7822,7824,7824,7826,7826,
810647828,7828,7830,7831,7832,7833,7834,7776,7836,7837,7838,7839,7840,7840,7842,
810657842,7844,7844,7846,7846,7848,7848,7850,7850,7852,7852,7854,7854,7856,7856,
810667858,7858,7860,7860,7862,7862,7864,7864,7866,7866,7868,7868,7870,7870,7872,
810677872,7874,7874,7876,7876,7878,7878,7880,7880,7882,7882,7884,7884,7886,7886,
810687888,7888,7890,7890,7892,7892,7894,7894,7896,7896,7898,7898,7900,7900,7902,
810697902,7904,7904,7906,7906,7908,7908,7910,7910,7912,7912,7914,7914,7916,7916,
810707918,7918,7920,7920,7922,7922,7924,7924,7926,7926,7928,7928,7930,7930,7932,
810717932,7934,7934,7944,7945,7946,7947,7948,7949,7950,7951,7944,7945,7946,7947,
810727948,7949,7950,7951,7960,7961,7962,7963,7964,7965,7958,7959,7960,7961,7962,
810737963,7964,7965,7966,7967,7976,7977,7978,7979,7980,7981,7982,7983,7976,7977,
810747978,7979,7980,7981,7982,7983,7992,7993,7994,7995,7996,7997,7998,7999,7992,
810757993,7994,7995,7996,7997,7998,7999,8008,8009,8010,8011,8012,8013,8006,8007,
810768008,8009,8010,8011,8012,8013,8014,8015,8016,8025,8018,8027,8020,8029,8022,
810778031,8024,8025,8026,8027,8028,8029,8030,8031,8040,8041,8042,8043,8044,8045,
810788046,8047,8040,8041,8042,8043,8044,8045,8046,8047,8122,8123,8136,8137,8138,
810798139,8154,8155,8184,8185,8170,8171,8186,8187,8062,8063,8064,8065,8066,8067,
810808068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080,8081,8082,
810818083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,
810828098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111,8120,
810838121,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,921,8127,
810848128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,
810858143,8152,8153,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,
810868158,8159,8168,8169,8162,8163,8164,8172,8166,8167,8168,8169,8170,8171,8172,
810878173,8174,8175,8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,
810888188,8189,8190,8191,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,
810898203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,
810908218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229,8230,8231,8232,
810918233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245,8246,8247,
810928248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261,8262,
810938263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277,
810948278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,
810958293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,
810968308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,
810978323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,
810988338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,
810998353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,
811008368,8369,8370,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382,
811018383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,
811028398,8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,
811038413,8414,8415,8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,
811048428,8429,8430,8431,8432,8433,8434,8435,8436,8437,8438,8439,8440,8441,8442,
811058443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,
811068458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,
811078473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485,8486,8487,
811088488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,
811098503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,
811108518,8519,8520,8521,8522,8523,8524,8525,8498,8527,8528,8529,8530,8531,8532,
811118533,8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,
811128548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8544,8545,8546,
811138547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8576,8577,
811148578,8579,8579,8581,8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,
811158593,8594,8595,8596,8597,8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,
811168608,8609,8610,8611,8612,8613,8614,8615,8616,8617,8618,8619,8620,8621,8622,
811178623,8624,8625,8626,8627,8628,8629,8630,8631,8632,8633,8634,8635,8636,8637,
811188638,8639,8640,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8651,8652,
811198653,8654,8655,8656,8657,8658,8659,8660,8661,8662,8663,8664,8665,8666,8667,
811208668,8669,8670,8671,8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,
811218683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,
811228698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709,8710,8711,8712,
811238713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725,8726,8727,
811248728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741,8742,
811258743,8744,8745,8746,8747,8748,8749,8750,8751,8752,8753,8754,8755,8756,8757,
811268758,8759,8760,8761,8762,8763,8764,8765,8766,8767,8768,8769,8770,8771,8772,
811278773,8774,8775,8776,8777,8778,8779,8780,8781,8782,8783,8784,8785,8786,8787,
811288788,8789,8790,8791,8792,8793,8794,8795,8796,8797,8798,8799,8800,8801,8802,
811298803,8804,8805,8806,8807,8808,8809,8810,8811,8812,8813,8814,8815,8816,8817,
811308818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,8829,8830,8831,8832,
811318833,8834,8835,8836,8837,8838,8839,8840,8841,8842,8843,8844,8845,8846,8847,
811328848,8849,8850,8851,8852,8853,8854,8855,8856,8857,8858,8859,8860,8861,8862,
811338863,8864,8865,8866,8867,8868,8869,8870,8871,8872,8873,8874,8875,8876,8877,
811348878,8879,8880,8881,8882,8883,8884,8885,8886,8887,8888,8889,8890,8891,8892,
811358893,8894,8895,8896,8897,8898,8899,8900,8901,8902,8903,8904,8905,8906,8907,
811368908,8909,8910,8911,8912,8913,8914,8915,8916,8917,8918,8919,8920,8921,8922,
811378923,8924,8925,8926,8927,8928,8929,8930,8931,8932,8933,8934,8935,8936,8937,
811388938,8939,8940,8941,8942,8943,8944,8945,8946,8947,8948,8949,8950,8951,8952,
811398953,8954,8955,8956,8957,8958,8959,8960,8961,8962,8963,8964,8965,8966,8967,
811408968,8969,8970,8971,8972,8973,8974,8975,8976,8977,8978,8979,8980,8981,8982,
811418983,8984,8985,8986,8987,8988,8989,8990,8991,8992,8993,8994,8995,8996,8997,
811428998,8999,9000,9001,9002,9003,9004,9005,9006,9007,9008,9009,9010,9011,9012,
811439013,9014,9015,9016,9017,9018,9019,9020,9021,9022,9023,9024,9025,9026,9027,
811449028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,
811459043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9056,9057,
811469058,9059,9060,9061,9062,9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,
811479073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085,9086,9087,
811489088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9101,9102,
811499103,9104,9105,9106,9107,9108,9109,9110,9111,9112,9113,9114,9115,9116,9117,
811509118,9119,9120,9121,9122,9123,9124,9125,9126,9127,9128,9129,9130,9131,9132,
811519133,9134,9135,9136,9137,9138,9139,9140,9141,9142,9143,9144,9145,9146,9147,
811529148,9149,9150,9151,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,
811539163,9164,9165,9166,9167,9168,9169,9170,9171,9172,9173,9174,9175,9176,9177,
811549178,9179,9180,9181,9182,9183,9184,9185,9186,9187,9188,9189,9190,9191,9192,
811559193,9194,9195,9196,9197,9198,9199,9200,9201,9202,9203,9204,9205,9206,9207,
811569208,9209,9210,9211,9212,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,
811579223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,
811589238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9248,9249,9250,9251,9252,
811599253,9254,9255,9256,9257,9258,9259,9260,9261,9262,9263,9264,9265,9266,9267,
811609268,9269,9270,9271,9272,9273,9274,9275,9276,9277,9278,9279,9280,9281,9282,
811619283,9284,9285,9286,9287,9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,
811629298,9299,9300,9301,9302,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,
811639313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,
811649328,9329,9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,
811659343,9344,9345,9346,9347,9348,9349,9350,9351,9352,9353,9354,9355,9356,9357,
811669358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9372,
811679373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,
811689388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9398,9399,9400,9401,9402,
811699403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,
811709418,9419,9420,9421,9422,9423,9398,9399,9400,9401,9402,9403,9404,9405,9406,
811719407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,
811729422,9423,9450,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,9461,9462,
811739463,9464,9465,9466,9467,9468,9469,9470,9471,9472,9473,9474,9475,9476,9477,
811749478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,
811759493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,
811769508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,
811779523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,
811789538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550,9551,9552,
811799553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,
811809568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,
811819583,9584,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,
811829598,9599,9600,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,
811839613,9614,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,
811849628,9629,9630,9631,9632,9633,9634,9635,9636,9637,9638,9639,9640,9641,9642,
811859643,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9654,9655,9656,9657,
811869658,9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,9670,9671,9672,
811879673,9674,9675,9676,9677,9678,9679,9680,9681,9682,9683,9684,9685,9686,9687,
811889688,9689,9690,9691,9692,9693,9694,9695,9696,9697,9698,9699,9700,9701,9702,
811899703,9704,9705,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715,9716,9717,
811909718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731,9732,
811919733,9734,9735,9736,9737,9738,9739,9740,9741,9742,9743,9744,9745,9746,9747,
811929748,9749,9750,9751,9752,9753,9754,9755,9756,9757,9758,9759,9760,9761,9762,
811939763,9764,9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,
811949778,9779,9780,9781,9782,9783,9784,9785,9786,9787,9788,9789,9790,9791,9792,
811959793,9794,9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,
811969808,9809,9810,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822,
811979823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9836,9837,
811989838,9839,9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,
811999853,9854,9855,9856,9857,9858,9859,9860,9861,9862,9863,9864,9865,9866,9867,
812009868,9869,9870,9871,9872,9873,9874,9875,9876,9877,9878,9879,9880,9881,9882,
812019883,9884,9885,9886,9887,9888,9889,9890,9891,9892,9893,9894,9895,9896,9897,
812029898,9899,9900,9901,9902,9903,9904,9905,9906,9907,9908,9909,9910,9911,9912,
812039913,9914,9915,9916,9917,9918,9919,9920,9921,9922,9923,9924,9925,9926,9927,
812049928,9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,
812059943,9944,9945,9946,9947,9948,9949,9950,9951,9952,9953,9954,9955,9956,9957,
812069958,9959,9960,9961,9962,9963,9964,9965,9966,9967,9968,9969,9970,9971,9972,
812079973,9974,9975,9976,9977,9978,9979,9980,9981,9982,9983,9984,9985,9986,9987,
812089988,9989,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999,10000,10001,
8120910002,10003,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,
8121010014,10015,10016,10017,10018,10019,10020,10021,10022,10023,10024,10025,
8121110026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10037,
8121210038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,10049,
8121310050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,
8121410062,10063,10064,10065,10066,10067,10068,10069,10070,10071,10072,10073,
8121510074,10075,10076,10077,10078,10079,10080,10081,10082,10083,10084,10085,
8121610086,10087,10088,10089,10090,10091,10092,10093,10094,10095,10096,10097,
8121710098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,
8121810110,10111,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,
8121910122,10123,10124,10125,10126,10127,10128,10129,10130,10131,10132,10133,
8122010134,10135,10136,10137,10138,10139,10140,10141,10142,10143,10144,10145,
8122110146,10147,10148,10149,10150,10151,10152,10153,10154,10155,10156,10157,
8122210158,10159,10160,10161,10162,10163,10164,10165,10166,10167,10168,10169,
8122310170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,
8122410182,10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,10193,
8122510194,10195,10196,10197,10198,10199,10200,10201,10202,10203,10204,10205,
8122610206,10207,10208,10209,10210,10211,10212,10213,10214,10215,10216,10217,
8122710218,10219,10220,10221,10222,10223,10224,10225,10226,10227,10228,10229,
8122810230,10231,10232,10233,10234,10235,10236,10237,10238,10239,10240,10241,
8122910242,10243,10244,10245,10246,10247,10248,10249,10250,10251,10252,10253,
8123010254,10255,10256,10257,10258,10259,10260,10261,10262,10263,10264,10265,
8123110266,10267,10268,10269,10270,10271,10272,10273,10274,10275,10276,10277,
8123210278,10279,10280,10281,10282,10283,10284,10285,10286,10287,10288,10289,
8123310290,10291,10292,10293,10294,10295,10296,10297,10298,10299,10300,10301,
8123410302,10303,10304,10305,10306,10307,10308,10309,10310,10311,10312,10313,
8123510314,10315,10316,10317,10318,10319,10320,10321,10322,10323,10324,10325,
8123610326,10327,10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,
8123710338,10339,10340,10341,10342,10343,10344,10345,10346,10347,10348,10349,
8123810350,10351,10352,10353,10354,10355,10356,10357,10358,10359,10360,10361,
8123910362,10363,10364,10365,10366,10367,10368,10369,10370,10371,10372,10373,
8124010374,10375,10376,10377,10378,10379,10380,10381,10382,10383,10384,10385,
8124110386,10387,10388,10389,10390,10391,10392,10393,10394,10395,10396,10397,
8124210398,10399,10400,10401,10402,10403,10404,10405,10406,10407,10408,10409,
8124310410,10411,10412,10413,10414,10415,10416,10417,10418,10419,10420,10421,
8124410422,10423,10424,10425,10426,10427,10428,10429,10430,10431,10432,10433,
8124510434,10435,10436,10437,10438,10439,10440,10441,10442,10443,10444,10445,
8124610446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10456,10457,
8124710458,10459,10460,10461,10462,10463,10464,10465,10466,10467,10468,10469,
8124810470,10471,10472,10473,10474,10475,10476,10477,10478,10479,10480,10481,
8124910482,10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,
8125010494,10495,10496,10497,10498,10499,10500,10501,10502,10503,10504,10505,
8125110506,10507,10508,10509,10510,10511,10512,10513,10514,10515,10516,10517,
8125210518,10519,10520,10521,10522,10523,10524,10525,10526,10527,10528,10529,
8125310530,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,
8125410542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552,10553,
8125510554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565,
8125610566,10567,10568,10569,10570,10571,10572,10573,10574,10575,10576,10577,
8125710578,10579,10580,10581,10582,10583,10584,10585,10586,10587,10588,10589,
8125810590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,
8125910602,10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,
8126010614,10615,10616,10617,10618,10619,10620,10621,10622,10623,10624,10625,
8126110626,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10637,
8126210638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648,10649,
8126310650,10651,10652,10653,10654,10655,10656,10657,10658,10659,10660,10661,
8126410662,10663,10664,10665,10666,10667,10668,10669,10670,10671,10672,10673,
8126510674,10675,10676,10677,10678,10679,10680,10681,10682,10683,10684,10685,
8126610686,10687,10688,10689,10690,10691,10692,10693,10694,10695,10696,10697,
8126710698,10699,10700,10701,10702,10703,10704,10705,10706,10707,10708,10709,
8126810710,10711,10712,10713,10714,10715,10716,10717,10718,10719,10720,10721,
8126910722,10723,10724,10725,10726,10727,10728,10729,10730,10731,10732,10733,
8127010734,10735,10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,
8127110746,10747,10748,10749,10750,10751,10752,10753,10754,10755,10756,10757,
8127210758,10759,10760,10761,10762,10763,10764,10765,10766,10767,10768,10769,
8127310770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780,10781,
8127410782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,
8127510794,10795,10796,10797,10798,10799,10800,10801,10802,10803,10804,10805,
8127610806,10807,10808,10809,10810,10811,10812,10813,10814,10815,10816,10817,
8127710818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10828,10829,
8127810830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10840,10841,
8127910842,10843,10844,10845,10846,10847,10848,10849,10850,10851,10852,10853,
8128010854,10855,10856,10857,10858,10859,10860,10861,10862,10863,10864,10865,
8128110866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876,10877,
8128210878,10879,10880,10881,10882,10883,10884,10885,10886,10887,10888,10889,
8128310890,10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,
8128410902,10903,10904,10905,10906,10907,10908,10909,10910,10911,10912,10913,
8128510914,10915,10916,10917,10918,10919,10920,10921,10922,10923,10924,10925,
8128610926,10927,10928,10929,10930,10931,10932,10933,10934,10935,10936,10937,
8128710938,10939,10940,10941,10942,10943,10944,10945,10946,10947,10948,10949,
8128810950,10951,10952,10953,10954,10955,10956,10957,10958,10959,10960,10961,
8128910962,10963,10964,10965,10966,10967,10968,10969,10970,10971,10972,10973,
8129010974,10975,10976,10977,10978,10979,10980,10981,10982,10983,10984,10985,
8129110986,10987,10988,10989,10990,10991,10992,10993,10994,10995,10996,10997,
8129210998,10999,11000,11001,11002,11003,11004,11005,11006,11007,11008,11009,
8129311010,11011,11012,11013,11014,11015,11016,11017,11018,11019,11020,11021,
8129411022,11023,11024,11025,11026,11027,11028,11029,11030,11031,11032,11033,
8129511034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044,11045,
8129611046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056,11057,
8129711058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,
8129811070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,
8129911082,11083,11084,11085,11086,11087,11088,11089,11090,11091,11092,11093,
8130011094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104,11105,
8130111106,11107,11108,11109,11110,11111,11112,11113,11114,11115,11116,11117,
8130211118,11119,11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,
8130311130,11131,11132,11133,11134,11135,11136,11137,11138,11139,11140,11141,
8130411142,11143,11144,11145,11146,11147,11148,11149,11150,11151,11152,11153,
8130511154,11155,11156,11157,11158,11159,11160,11161,11162,11163,11164,11165,
8130611166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,
8130711178,11179,11180,11181,11182,11183,11184,11185,11186,11187,11188,11189,
8130811190,11191,11192,11193,11194,11195,11196,11197,11198,11199,11200,11201,
8130911202,11203,11204,11205,11206,11207,11208,11209,11210,11211,11212,11213,
8131011214,11215,11216,11217,11218,11219,11220,11221,11222,11223,11224,11225,
8131111226,11227,11228,11229,11230,11231,11232,11233,11234,11235,11236,11237,
8131211238,11239,11240,11241,11242,11243,11244,11245,11246,11247,11248,11249,
8131311250,11251,11252,11253,11254,11255,11256,11257,11258,11259,11260,11261,
8131411262,11263,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
8131511274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
8131611286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
8131711298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
8131811310,11311,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
8131911274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
8132011286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
8132111298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
8132211310,11359,11360,11360,11362,11363,11364,570,574,11367,11367,11369,11369,
8132311371,11371,11373,11374,11375,11376,11377,11378,11378,11380,11381,11381,
8132411383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11392,11394,
8132511394,11396,11396,11398,11398,11400,11400,11402,11402,11404,11404,11406,
8132611406,11408,11408,11410,11410,11412,11412,11414,11414,11416,11416,11418,
8132711418,11420,11420,11422,11422,11424,11424,11426,11426,11428,11428,11430,
8132811430,11432,11432,11434,11434,11436,11436,11438,11438,11440,11440,11442,
8132911442,11444,11444,11446,11446,11448,11448,11450,11450,11452,11452,11454,
8133011454,11456,11456,11458,11458,11460,11460,11462,11462,11464,11464,11466,
8133111466,11468,11468,11470,11470,11472,11472,11474,11474,11476,11476,11478,
8133211478,11480,11480,11482,11482,11484,11484,11486,11486,11488,11488,11490,
8133311490,11492,11493,11494,11495,11496,11497,11498,11499,11499,11501,11501,
8133411503,11504,11505,11506,11507,11508,11509,11510,11511,11512,11513,11514,
8133511515,11516,11517,11518,11519,4256,4257,4258,4259,4260,4261,4262,4263,4264,
813364265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,
813374280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,
8133811558,11559,11560,11561,11562,11563,11564,11565,11566,11567,11568,11569,
8133911570,11571,11572,11573,11574,11575,11576,11577,11578,11579,11580,11581,
8134011582,11583,11584,11585,11586,11587,11588,11589,11590,11591,11592,11593,
8134111594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,11605,
8134211606,11607,11608,11609,11610,11611,11612,11613,11614,11615,11616,11617,
8134311618,11619,11620,11621,11622,11623,11624,11625,11626,11627,11628,11629,
8134411630,11631,11632,11633,11634,11635,11636,11637,11638,11639,11640,11641,
8134511642,11643,11644,11645,11646,11647,11648,11649,11650,11651,11652,11653,
8134611654,11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,
8134711666,11667,11668,11669,11670,11671,11672,11673,11674,11675,11676,11677,
8134811678,11679,11680,11681,11682,11683,11684,11685,11686,11687,11688,11689,
8134911690,11691,11692,11693,11694,11695,11696,11697,11698,11699,11700,11701,
8135011702,11703,11704,11705,11706,11707,11708,11709,11710,11711,11712,11713,
8135111714,11715,11716,11717,11718,11719,11720,11721,11722,11723,11724,11725,
8135211726,11727,11728,11729,11730,11731,11732,11733,11734,11735,11736,11737,
8135311738,11739,11740,11741,11742,11743,11744,11745,11746,11747,11748,11749,
8135411750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,
8135511762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,
8135611774,11775,11776,11777,11778,11779,11780,11781,11782,11783,11784,11785,
8135711786,11787,11788,11789,11790,11791,11792,11793,11794,11795,11796,11797,
8135811798,11799,11800,11801,11802,11803,11804,11805,11806,11807,11808,11809,
8135911810,11811,11812,11813,11814,11815,11816,11817,11818,11819,11820,11821,
8136011822,11823,11824,11825,11826,11827,11828,11829,11830,11831,11832,11833,
8136111834,11835,11836,11837,11838,11839,11840,11841,11842,11843,11844,11845,
8136211846,11847,11848,11849,11850,11851,11852,11853,11854,11855,11856,11857,
8136311858,11859,11860,11861,11862,11863,11864,11865,11866,11867,11868,11869,
8136411870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,
8136511882,11883,11884,11885,11886,11887,11888,11889,11890,11891,11892,11893,
8136611894,11895,11896,11897,11898,11899,11900,11901,11902,11903,11904,11905,
8136711906,11907,11908,11909,11910,11911,11912,11913,11914,11915,11916,11917,
8136811918,11919,11920,11921,11922,11923,11924,11925,11926,11927,11928,11929,
8136911930,11931,11932,11933,11934,11935,11936,11937,11938,11939,11940,11941,
8137011942,11943,11944,11945,11946,11947,11948,11949,11950,11951,11952,11953,
8137111954,11955,11956,11957,11958,11959,11960,11961,11962,11963,11964,11965,
8137211966,11967,11968,11969,11970,11971,11972,11973,11974,11975,11976,11977,
8137311978,11979,11980,11981,11982,11983,11984,11985,11986,11987,11988,11989,
8137411990,11991,11992,11993,11994,11995,11996,11997,11998,11999,12000,12001,
8137512002,12003,12004,12005,12006,12007,12008,12009,12010,12011,12012,12013,
8137612014,12015,12016,12017,12018,12019,12020,12021,12022,12023,12024,12025,
8137712026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037,
8137812038,12039,12040,12041,12042,12043,12044,12045,12046,12047,12048,12049,
8137912050,12051,12052,12053,12054,12055,12056,12057,12058,12059,12060,12061,
8138012062,12063,12064,12065,12066,12067,12068,12069,12070,12071,12072,12073,
8138112074,12075,12076,12077,12078,12079,12080,12081,12082,12083,12084,12085,
8138212086,12087,12088,12089,12090,12091,12092,12093,12094,12095,12096,12097,
8138312098,12099,12100,12101,12102,12103,12104,12105,12106,12107,12108,12109,
8138412110,12111,12112,12113,12114,12115,12116,12117,12118,12119,12120,12121,
8138512122,12123,12124,12125,12126,12127,12128,12129,12130,12131,12132,12133,
8138612134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,
8138712146,12147,12148,12149,12150,12151,12152,12153,12154,12155,12156,12157,
8138812158,12159,12160,12161,12162,12163,12164,12165,12166,12167,12168,12169,
8138912170,12171,12172,12173,12174,12175,12176,12177,12178,12179,12180,12181,
8139012182,12183,12184,12185,12186,12187,12188,12189,12190,12191,12192,12193,
8139112194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204,12205,
8139212206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,
8139312218,12219,12220,12221,12222,12223,12224,12225,12226,12227,12228,12229,
8139412230,12231,12232,12233,12234,12235,12236,12237,12238,12239,12240,12241,
8139512242,12243,12244,12245,12246,12247,12248,12249,12250,12251,12252,12253,
8139612254,12255,12256,12257,12258,12259,12260,12261,12262,12263,12264,12265,
8139712266,12267,12268,12269,12270,12271,12272,12273,12274,12275,12276,12277,
8139812278,12279,12280,12281,12282,12283,12284,12285,12286,12287,12288,12289,
8139912290,12291,12292,12293,12294,12295,12296,12297,12298,12299,12300,12301,
8140012302,12303,12304,12305,12306,12307,12308,12309,12310,12311,12312,12313,
8140112314,12315,12316,12317,12318,12319,12320,12321,12322,12323,12324,12325,
8140212326,12327,12328,12329,12330,12331,12332,12333,12334,12335,12336,12337,
8140312338,12339,12340,12341,12342,12343,12344,12345,12346,12347,12348,12349,
8140412350,12351,12352,12353,12354,12355,12356,12357,12358,12359,12360,12361,
8140512362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,
8140612374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,
8140712386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,
8140812398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,
8140912410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,
8141012422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,
8141112434,12435,12436,12437,12438,12439,12440,12441,12442,12443,12444,12445,
8141212446,12447,12448,12449,12450,12451,12452,12453,12454,12455,12456,12457,
8141312458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,
8141412470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,
8141512482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,
8141612494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,
8141712506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,
8141812518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,
8141912530,12531,12532,12533,12534,12535,12536,12537,12538,12539,12540,12541,
8142012542,12543,12544,12545,12546,12547,12548,12549,12550,12551,12552,12553,
8142112554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,
8142212566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,
8142312578,12579,12580,12581,12582,12583,12584,12585,12586,12587,12588,12589,
8142412590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600,12601,
8142512602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,
8142612614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,
8142712626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,
8142812638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,
8142912650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,
8143012662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,
8143112674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,
8143212686,12687,12688,12689,12690,12691,12692,12693,12694,12695,12696,12697,
8143312698,12699,12700,12701,12702,12703,12704,12705,12706,12707,12708,12709,
8143412710,12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,
8143512722,12723,12724,12725,12726,12727,12728,12729,12730,12731,12732,12733,
8143612734,12735,12736,12737,12738,12739,12740,12741,12742,12743,12744,12745,
8143712746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,
8143812758,12759,12760,12761,12762,12763,12764,12765,12766,12767,12768,12769,
8143912770,12771,12772,12773,12774,12775,12776,12777,12778,12779,12780,12781,
8144012782,12783,12784,12785,12786,12787,12788,12789,12790,12791,12792,12793,
8144112794,12795,12796,12797,12798,12799,12800,12801,12802,12803,12804,12805,
8144212806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,
8144312818,12819,12820,12821,12822,12823,12824,12825,12826,12827,12828,12829,
8144412830,12831,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,
8144512842,12843,12844,12845,12846,12847,12848,12849,12850,12851,12852,12853,
8144612854,12855,12856,12857,12858,12859,12860,12861,12862,12863,12864,12865,
8144712866,12867,12868,12869,12870,12871,12872,12873,12874,12875,12876,12877,
8144812878,12879,12880,12881,12882,12883,12884,12885,12886,12887,12888,12889,
8144912890,12891,12892,12893,12894,12895,12896,12897,12898,12899,12900,12901,
8145012902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,
8145112914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,
8145212926,12927,12928,12929,12930,12931,12932,12933,12934,12935,12936,12937,
8145312938,12939,12940,12941,12942,12943,12944,12945,12946,12947,12948,12949,
8145412950,12951,12952,12953,12954,12955,12956,12957,12958,12959,12960,12961,
8145512962,12963,12964,12965,12966,12967,12968,12969,12970,12971,12972,12973,
8145612974,12975,12976,12977,12978,12979,12980,12981,12982,12983,12984,12985,
8145712986,12987,12988,12989,12990,12991,12992,12993,12994,12995,12996,12997,
8145812998,12999,13000,13001,13002,13003,13004,13005,13006,13007,13008,13009,
8145913010,13011,13012,13013,13014,13015,13016,13017,13018,13019,13020,13021,
8146013022,13023,13024,13025,13026,13027,13028,13029,13030,13031,13032,13033,
8146113034,13035,13036,13037,13038,13039,13040,13041,13042,13043,13044,13045,
8146213046,13047,13048,13049,13050,13051,13052,13053,13054,13055,13056,13057,
8146313058,13059,13060,13061,13062,13063,13064,13065,13066,13067,13068,13069,
8146413070,13071,13072,13073,13074,13075,13076,13077,13078,13079,13080,13081,
8146513082,13083,13084,13085,13086,13087,13088,13089,13090,13091,13092,13093,
8146613094,13095,13096,13097,13098,13099,13100,13101,13102,13103,13104,13105,
8146713106,13107,13108,13109,13110,13111,13112,13113,13114,13115,13116,13117,
8146813118,13119,13120,13121,13122,13123,13124,13125,13126,13127,13128,13129,
8146913130,13131,13132,13133,13134,13135,13136,13137,13138,13139,13140,13141,
8147013142,13143,13144,13145,13146,13147,13148,13149,13150,13151,13152,13153,
8147113154,13155,13156,13157,13158,13159,13160,13161,13162,13163,13164,13165,
8147213166,13167,13168,13169,13170,13171,13172,13173,13174,13175,13176,13177,
8147313178,13179,13180,13181,13182,13183,13184,13185,13186,13187,13188,13189,
8147413190,13191,13192,13193,13194,13195,13196,13197,13198,13199,13200,13201,
8147513202,13203,13204,13205,13206,13207,13208,13209,13210,13211,13212,13213,
8147613214,13215,13216,13217,13218,13219,13220,13221,13222,13223,13224,13225,
8147713226,13227,13228,13229,13230,13231,13232,13233,13234,13235,13236,13237,
8147813238,13239,13240,13241,13242,13243,13244,13245,13246,13247,13248,13249,
8147913250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260,13261,
8148013262,13263,13264,13265,13266,13267,13268,13269,13270,13271,13272,13273,
8148113274,13275,13276,13277,13278,13279,13280,13281,13282,13283,13284,13285,
8148213286,13287,13288,13289,13290,13291,13292,13293,13294,13295,13296,13297,
8148313298,13299,13300,13301,13302,13303,13304,13305,13306,13307,13308,13309,
8148413310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321,
8148513322,13323,13324,13325,13326,13327,13328,13329,13330,13331,13332,13333,
8148613334,13335,13336,13337,13338,13339,13340,13341,13342,13343,13344,13345,
8148713346,13347,13348,13349,13350,13351,13352,13353,13354,13355,13356,13357,
8148813358,13359,13360,13361,13362,13363,13364,13365,13366,13367,13368,13369,
8148913370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,
8149013382,13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,
8149113394,13395,13396,13397,13398,13399,13400,13401,13402,13403,13404,13405,
8149213406,13407,13408,13409,13410,13411,13412,13413,13414,13415,13416,13417,
8149313418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,
8149413430,13431,13432,13433,13434,13435,13436,13437,13438,13439,13440,13441,
8149513442,13443,13444,13445,13446,13447,13448,13449,13450,13451,13452,13453,
8149613454,13455,13456,13457,13458,13459,13460,13461,13462,13463,13464,13465,
8149713466,13467,13468,13469,13470,13471,13472,13473,13474,13475,13476,13477,
8149813478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,
8149913490,13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,
8150013502,13503,13504,13505,13506,13507,13508,13509,13510,13511,13512,13513,
8150113514,13515,13516,13517,13518,13519,13520,13521,13522,13523,13524,13525,
8150213526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,
8150313538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,
8150413550,13551,13552,13553,13554,13555,13556,13557,13558,13559,13560,13561,
8150513562,13563,13564,13565,13566,13567,13568,13569,13570,13571,13572,13573,
8150613574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,
8150713586,13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,
8150813598,13599,13600,13601,13602,13603,13604,13605,13606,13607,13608,13609,
8150913610,13611,13612,13613,13614,13615,13616,13617,13618,13619,13620,13621,
8151013622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,
8151113634,13635,13636,13637,13638,13639,13640,13641,13642,13643,13644,13645,
8151213646,13647,13648,13649,13650,13651,13652,13653,13654,13655,13656,13657,
8151313658,13659,13660,13661,13662,13663,13664,13665,13666,13667,13668,13669,
8151413670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680,13681,
8151513682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,
8151613694,13695,13696,13697,13698,13699,13700,13701,13702,13703,13704,13705,
8151713706,13707,13708,13709,13710,13711,13712,13713,13714,13715,13716,13717,
8151813718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728,13729,
8151913730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,
8152013742,13743,13744,13745,13746,13747,13748,13749,13750,13751,13752,13753,
8152113754,13755,13756,13757,13758,13759,13760,13761,13762,13763,13764,13765,
8152213766,13767,13768,13769,13770,13771,13772,13773,13774,13775,13776,13777,
8152313778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,
8152413790,13791,13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,
8152513802,13803,13804,13805,13806,13807,13808,13809,13810,13811,13812,13813,
8152613814,13815,13816,13817,13818,13819,13820,13821,13822,13823,13824,13825,
8152713826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,
8152813838,13839,13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,
8152913850,13851,13852,13853,13854,13855,13856,13857,13858,13859,13860,13861,
8153013862,13863,13864,13865,13866,13867,13868,13869,13870,13871,13872,13873,
8153113874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,
8153213886,13887,13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,
8153313898,13899,13900,13901,13902,13903,13904,13905,13906,13907,13908,13909,
8153413910,13911,13912,13913,13914,13915,13916,13917,13918,13919,13920,13921,
8153513922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,
8153613934,13935,13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,
8153713946,13947,13948,13949,13950,13951,13952,13953,13954,13955,13956,13957,
8153813958,13959,13960,13961,13962,13963,13964,13965,13966,13967,13968,13969,
8153913970,13971,13972,13973,13974,13975,13976,13977,13978,13979,13980,13981,
8154013982,13983,13984,13985,13986,13987,13988,13989,13990,13991,13992,13993,
8154113994,13995,13996,13997,13998,13999,14000,14001,14002,14003,14004,14005,
8154214006,14007,14008,14009,14010,14011,14012,14013,14014,14015,14016,14017,
8154314018,14019,14020,14021,14022,14023,14024,14025,14026,14027,14028,14029,
8154414030,14031,14032,14033,14034,14035,14036,14037,14038,14039,14040,14041,
8154514042,14043,14044,14045,14046,14047,14048,14049,14050,14051,14052,14053,
8154614054,14055,14056,14057,14058,14059,14060,14061,14062,14063,14064,14065,
8154714066,14067,14068,14069,14070,14071,14072,14073,14074,14075,14076,14077,
8154814078,14079,14080,14081,14082,14083,14084,14085,14086,14087,14088,14089,
8154914090,14091,14092,14093,14094,14095,14096,14097,14098,14099,14100,14101,
8155014102,14103,14104,14105,14106,14107,14108,14109,14110,14111,14112,14113,
8155114114,14115,14116,14117,14118,14119,14120,14121,14122,14123,14124,14125,
8155214126,14127,14128,14129,14130,14131,14132,14133,14134,14135,14136,14137,
8155314138,14139,14140,14141,14142,14143,14144,14145,14146,14147,14148,14149,
8155414150,14151,14152,14153,14154,14155,14156,14157,14158,14159,14160,14161,
8155514162,14163,14164,14165,14166,14167,14168,14169,14170,14171,14172,14173,
8155614174,14175,14176,14177,14178,14179,14180,14181,14182,14183,14184,14185,
8155714186,14187,14188,14189,14190,14191,14192,14193,14194,14195,14196,14197,
8155814198,14199,14200,14201,14202,14203,14204,14205,14206,14207,14208,14209,
8155914210,14211,14212,14213,14214,14215,14216,14217,14218,14219,14220,14221,
8156014222,14223,14224,14225,14226,14227,14228,14229,14230,14231,14232,14233,
8156114234,14235,14236,14237,14238,14239,14240,14241,14242,14243,14244,14245,
8156214246,14247,14248,14249,14250,14251,14252,14253,14254,14255,14256,14257,
8156314258,14259,14260,14261,14262,14263,14264,14265,14266,14267,14268,14269,
8156414270,14271,14272,14273,14274,14275,14276,14277,14278,14279,14280,14281,
8156514282,14283,14284,14285,14286,14287,14288,14289,14290,14291,14292,14293,
8156614294,14295,14296,14297,14298,14299,14300,14301,14302,14303,14304,14305,
8156714306,14307,14308,14309,14310,14311,14312,14313,14314,14315,14316,14317,
8156814318,14319,14320,14321,14322,14323,14324,14325,14326,14327,14328,14329,
8156914330,14331,14332,14333,14334,14335,14336,14337,14338,14339,14340,14341,
8157014342,14343,14344,14345,14346,14347,14348,14349,14350,14351,14352,14353,
8157114354,14355,14356,14357,14358,14359,14360,14361,14362,14363,14364,14365,
8157214366,14367,14368,14369,14370,14371,14372,14373,14374,14375,14376,14377,
8157314378,14379,14380,14381,14382,14383,14384,14385,14386,14387,14388,14389,
8157414390,14391,14392,14393,14394,14395,14396,14397,14398,14399,14400,14401,
8157514402,14403,14404,14405,14406,14407,14408,14409,14410,14411,14412,14413,
8157614414,14415,14416,14417,14418,14419,14420,14421,14422,14423,14424,14425,
8157714426,14427,14428,14429,14430,14431,14432,14433,14434,14435,14436,14437,
8157814438,14439,14440,14441,14442,14443,14444,14445,14446,14447,14448,14449,
8157914450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,
8158014462,14463,14464,14465,14466,14467,14468,14469,14470,14471,14472,14473,
8158114474,14475,14476,14477,14478,14479,14480,14481,14482,14483,14484,14485,
8158214486,14487,14488,14489,14490,14491,14492,14493,14494,14495,14496,14497,
8158314498,14499,14500,14501,14502,14503,14504,14505,14506,14507,14508,14509,
8158414510,14511,14512,14513,14514,14515,14516,14517,14518,14519,14520,14521,
8158514522,14523,14524,14525,14526,14527,14528,14529,14530,14531,14532,14533,
8158614534,14535,14536,14537,14538,14539,14540,14541,14542,14543,14544,14545,
8158714546,14547,14548,14549,14550,14551,14552,14553,14554,14555,14556,14557,
8158814558,14559,14560,14561,14562,14563,14564,14565,14566,14567,14568,14569,
8158914570,14571,14572,14573,14574,14575,14576,14577,14578,14579,14580,14581,
8159014582,14583,14584,14585,14586,14587,14588,14589,14590,14591,14592,14593,
8159114594,14595,14596,14597,14598,14599,14600,14601,14602,14603,14604,14605,
8159214606,14607,14608,14609,14610,14611,14612,14613,14614,14615,14616,14617,
8159314618,14619,14620,14621,14622,14623,14624,14625,14626,14627,14628,14629,
8159414630,14631,14632,14633,14634,14635,14636,14637,14638,14639,14640,14641,
8159514642,14643,14644,14645,14646,14647,14648,14649,14650,14651,14652,14653,
8159614654,14655,14656,14657,14658,14659,14660,14661,14662,14663,14664,14665,
8159714666,14667,14668,14669,14670,14671,14672,14673,14674,14675,14676,14677,
8159814678,14679,14680,14681,14682,14683,14684,14685,14686,14687,14688,14689,
8159914690,14691,14692,14693,14694,14695,14696,14697,14698,14699,14700,14701,
8160014702,14703,14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,
8160114714,14715,14716,14717,14718,14719,14720,14721,14722,14723,14724,14725,
8160214726,14727,14728,14729,14730,14731,14732,14733,14734,14735,14736,14737,
8160314738,14739,14740,14741,14742,14743,14744,14745,14746,14747,14748,14749,
8160414750,14751,14752,14753,14754,14755,14756,14757,14758,14759,14760,14761,
8160514762,14763,14764,14765,14766,14767,14768,14769,14770,14771,14772,14773,
8160614774,14775,14776,14777,14778,14779,14780,14781,14782,14783,14784,14785,
8160714786,14787,14788,14789,14790,14791,14792,14793,14794,14795,14796,14797,
8160814798,14799,14800,14801,14802,14803,14804,14805,14806,14807,14808,14809,
8160914810,14811,14812,14813,14814,14815,14816,14817,14818,14819,14820,14821,
8161014822,14823,14824,14825,14826,14827,14828,14829,14830,14831,14832,14833,
8161114834,14835,14836,14837,14838,14839,14840,14841,14842,14843,14844,14845,
8161214846,14847,14848,14849,14850,14851,14852,14853,14854,14855,14856,14857,
8161314858,14859,14860,14861,14862,14863,14864,14865,14866,14867,14868,14869,
8161414870,14871,14872,14873,14874,14875,14876,14877,14878,14879,14880,14881,
8161514882,14883,14884,14885,14886,14887,14888,14889,14890,14891,14892,14893,
8161614894,14895,14896,14897,14898,14899,14900,14901,14902,14903,14904,14905,
8161714906,14907,14908,14909,14910,14911,14912,14913,14914,14915,14916,14917,
8161814918,14919,14920,14921,14922,14923,14924,14925,14926,14927,14928,14929,
8161914930,14931,14932,14933,14934,14935,14936,14937,14938,14939,14940,14941,
8162014942,14943,14944,14945,14946,14947,14948,14949,14950,14951,14952,14953,
8162114954,14955,14956,14957,14958,14959,14960,14961,14962,14963,14964,14965,
8162214966,14967,14968,14969,14970,14971,14972,14973,14974,14975,14976,14977,
8162314978,14979,14980,14981,14982,14983,14984,14985,14986,14987,14988,14989,
8162414990,14991,14992,14993,14994,14995,14996,14997,14998,14999,15000,15001,
8162515002,15003,15004,15005,15006,15007,15008,15009,15010,15011,15012,15013,
8162615014,15015,15016,15017,15018,15019,15020,15021,15022,15023,15024,15025,
8162715026,15027,15028,15029,15030,15031,15032,15033,15034,15035,15036,15037,
8162815038,15039,15040,15041,15042,15043,15044,15045,15046,15047,15048,15049,
8162915050,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,
8163015062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,
8163115074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,
8163215086,15087,15088,15089,15090,15091,15092,15093,15094,15095,15096,15097,
8163315098,15099,15100,15101,15102,15103,15104,15105,15106,15107,15108,15109,
8163415110,15111,15112,15113,15114,15115,15116,15117,15118,15119,15120,15121,
8163515122,15123,15124,15125,15126,15127,15128,15129,15130,15131,15132,15133,
8163615134,15135,15136,15137,15138,15139,15140,15141,15142,15143,15144,15145,
8163715146,15147,15148,15149,15150,15151,15152,15153,15154,15155,15156,15157,
8163815158,15159,15160,15161,15162,15163,15164,15165,15166,15167,15168,15169,
8163915170,15171,15172,15173,15174,15175,15176,15177,15178,15179,15180,15181,
8164015182,15183,15184,15185,15186,15187,15188,15189,15190,15191,15192,15193,
8164115194,15195,15196,15197,15198,15199,15200,15201,15202,15203,15204,15205,
8164215206,15207,15208,15209,15210,15211,15212,15213,15214,15215,15216,15217,
8164315218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15229,
8164415230,15231,15232,15233,15234,15235,15236,15237,15238,15239,15240,15241,
8164515242,15243,15244,15245,15246,15247,15248,15249,15250,15251,15252,15253,
8164615254,15255,15256,15257,15258,15259,15260,15261,15262,15263,15264,15265,
8164715266,15267,15268,15269,15270,15271,15272,15273,15274,15275,15276,15277,
8164815278,15279,15280,15281,15282,15283,15284,15285,15286,15287,15288,15289,
8164915290,15291,15292,15293,15294,15295,15296,15297,15298,15299,15300,15301,
8165015302,15303,15304,15305,15306,15307,15308,15309,15310,15311,15312,15313,
8165115314,15315,15316,15317,15318,15319,15320,15321,15322,15323,15324,15325,
8165215326,15327,15328,15329,15330,15331,15332,15333,15334,15335,15336,15337,
8165315338,15339,15340,15341,15342,15343,15344,15345,15346,15347,15348,15349,
8165415350,15351,15352,15353,15354,15355,15356,15357,15358,15359,15360,15361,
8165515362,15363,15364,15365,15366,15367,15368,15369,15370,15371,15372,15373,
8165615374,15375,15376,15377,15378,15379,15380,15381,15382,15383,15384,15385,
8165715386,15387,15388,15389,15390,15391,15392,15393,15394,15395,15396,15397,
8165815398,15399,15400,15401,15402,15403,15404,15405,15406,15407,15408,15409,
8165915410,15411,15412,15413,15414,15415,15416,15417,15418,15419,15420,15421,
8166015422,15423,15424,15425,15426,15427,15428,15429,15430,15431,15432,15433,
8166115434,15435,15436,15437,15438,15439,15440,15441,15442,15443,15444,15445,
8166215446,15447,15448,15449,15450,15451,15452,15453,15454,15455,15456,15457,
8166315458,15459,15460,15461,15462,15463,15464,15465,15466,15467,15468,15469,
8166415470,15471,15472,15473,15474,15475,15476,15477,15478,15479,15480,15481,
8166515482,15483,15484,15485,15486,15487,15488,15489,15490,15491,15492,15493,
8166615494,15495,15496,15497,15498,15499,15500,15501,15502,15503,15504,15505,
8166715506,15507,15508,15509,15510,15511,15512,15513,15514,15515,15516,15517,
8166815518,15519,15520,15521,15522,15523,15524,15525,15526,15527,15528,15529,
8166915530,15531,15532,15533,15534,15535,15536,15537,15538,15539,15540,15541,
8167015542,15543,15544,15545,15546,15547,15548,15549,15550,15551,15552,15553,
8167115554,15555,15556,15557,15558,15559,15560,15561,15562,15563,15564,15565,
8167215566,15567,15568,15569,15570,15571,15572,15573,15574,15575,15576,15577,
8167315578,15579,15580,15581,15582,15583,15584,15585,15586,15587,15588,15589,
8167415590,15591,15592,15593,15594,15595,15596,15597,15598,15599,15600,15601,
8167515602,15603,15604,15605,15606,15607,15608,15609,15610,15611,15612,15613,
8167615614,15615,15616,15617,15618,15619,15620,15621,15622,15623,15624,15625,
8167715626,15627,15628,15629,15630,15631,15632,15633,15634,15635,15636,15637,
8167815638,15639,15640,15641,15642,15643,15644,15645,15646,15647,15648,15649,
8167915650,15651,15652,15653,15654,15655,15656,15657,15658,15659,15660,15661,
8168015662,15663,15664,15665,15666,15667,15668,15669,15670,15671,15672,15673,
8168115674,15675,15676,15677,15678,15679,15680,15681,15682,15683,15684,15685,
8168215686,15687,15688,15689,15690,15691,15692,15693,15694,15695,15696,15697,
8168315698,15699,15700,15701,15702,15703,15704,15705,15706,15707,15708,15709,
8168415710,15711,15712,15713,15714,15715,15716,15717,15718,15719,15720,15721,
8168515722,15723,15724,15725,15726,15727,15728,15729,15730,15731,15732,15733,
8168615734,15735,15736,15737,15738,15739,15740,15741,15742,15743,15744,15745,
8168715746,15747,15748,15749,15750,15751,15752,15753,15754,15755,15756,15757,
8168815758,15759,15760,15761,15762,15763,15764,15765,15766,15767,15768,15769,
8168915770,15771,15772,15773,15774,15775,15776,15777,15778,15779,15780,15781,
8169015782,15783,15784,15785,15786,15787,15788,15789,15790,15791,15792,15793,
8169115794,15795,15796,15797,15798,15799,15800,15801,15802,15803,15804,15805,
8169215806,15807,15808,15809,15810,15811,15812,15813,15814,15815,15816,15817,
8169315818,15819,15820,15821,15822,15823,15824,15825,15826,15827,15828,15829,
8169415830,15831,15832,15833,15834,15835,15836,15837,15838,15839,15840,15841,
8169515842,15843,15844,15845,15846,15847,15848,15849,15850,15851,15852,15853,
8169615854,15855,15856,15857,15858,15859,15860,15861,15862,15863,15864,15865,
8169715866,15867,15868,15869,15870,15871,15872,15873,15874,15875,15876,15877,
8169815878,15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,
8169915890,15891,15892,15893,15894,15895,15896,15897,15898,15899,15900,15901,
8170015902,15903,15904,15905,15906,15907,15908,15909,15910,15911,15912,15913,
8170115914,15915,15916,15917,15918,15919,15920,15921,15922,15923,15924,15925,
8170215926,15927,15928,15929,15930,15931,15932,15933,15934,15935,15936,15937,
8170315938,15939,15940,15941,15942,15943,15944,15945,15946,15947,15948,15949,
8170415950,15951,15952,15953,15954,15955,15956,15957,15958,15959,15960,15961,
8170515962,15963,15964,15965,15966,15967,15968,15969,15970,15971,15972,15973,
8170615974,15975,15976,15977,15978,15979,15980,15981,15982,15983,15984,15985,
8170715986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,
8170815998,15999,16000,16001,16002,16003,16004,16005,16006,16007,16008,16009,
8170916010,16011,16012,16013,16014,16015,16016,16017,16018,16019,16020,16021,
8171016022,16023,16024,16025,16026,16027,16028,16029,16030,16031,16032,16033,
8171116034,16035,16036,16037,16038,16039,16040,16041,16042,16043,16044,16045,
8171216046,16047,16048,16049,16050,16051,16052,16053,16054,16055,16056,16057,
8171316058,16059,16060,16061,16062,16063,16064,16065,16066,16067,16068,16069,
8171416070,16071,16072,16073,16074,16075,16076,16077,16078,16079,16080,16081,
8171516082,16083,16084,16085,16086,16087,16088,16089,16090,16091,16092,16093,
8171616094,16095,16096,16097,16098,16099,16100,16101,16102,16103,16104,16105,
8171716106,16107,16108,16109,16110,16111,16112,16113,16114,16115,16116,16117,
8171816118,16119,16120,16121,16122,16123,16124,16125,16126,16127,16128,16129,
8171916130,16131,16132,16133,16134,16135,16136,16137,16138,16139,16140,16141,
8172016142,16143,16144,16145,16146,16147,16148,16149,16150,16151,16152,16153,
8172116154,16155,16156,16157,16158,16159,16160,16161,16162,16163,16164,16165,
8172216166,16167,16168,16169,16170,16171,16172,16173,16174,16175,16176,16177,
8172316178,16179,16180,16181,16182,16183,16184,16185,16186,16187,16188,16189,
8172416190,16191,16192,16193,16194,16195,16196,16197,16198,16199,16200,16201,
8172516202,16203,16204,16205,16206,16207,16208,16209,16210,16211,16212,16213,
8172616214,16215,16216,16217,16218,16219,16220,16221,16222,16223,16224,16225,
8172716226,16227,16228,16229,16230,16231,16232,16233,16234,16235,16236,16237,
8172816238,16239,16240,16241,16242,16243,16244,16245,16246,16247,16248,16249,
8172916250,16251,16252,16253,16254,16255,16256,16257,16258,16259,16260,16261,
8173016262,16263,16264,16265,16266,16267,16268,16269,16270,16271,16272,16273,
8173116274,16275,16276,16277,16278,16279,16280,16281,16282,16283,16284,16285,
8173216286,16287,16288,16289,16290,16291,16292,16293,16294,16295,16296,16297,
8173316298,16299,16300,16301,16302,16303,16304,16305,16306,16307,16308,16309,
8173416310,16311,16312,16313,16314,16315,16316,16317,16318,16319,16320,16321,
8173516322,16323,16324,16325,16326,16327,16328,16329,16330,16331,16332,16333,
8173616334,16335,16336,16337,16338,16339,16340,16341,16342,16343,16344,16345,
8173716346,16347,16348,16349,16350,16351,16352,16353,16354,16355,16356,16357,
8173816358,16359,16360,16361,16362,16363,16364,16365,16366,16367,16368,16369,
8173916370,16371,16372,16373,16374,16375,16376,16377,16378,16379,16380,16381,
8174016382,16383,16384,16385,16386,16387,16388,16389,16390,16391,16392,16393,
8174116394,16395,16396,16397,16398,16399,16400,16401,16402,16403,16404,16405,
8174216406,16407,16408,16409,16410,16411,16412,16413,16414,16415,16416,16417,
8174316418,16419,16420,16421,16422,16423,16424,16425,16426,16427,16428,16429,
8174416430,16431,16432,16433,16434,16435,16436,16437,16438,16439,16440,16441,
8174516442,16443,16444,16445,16446,16447,16448,16449,16450,16451,16452,16453,
8174616454,16455,16456,16457,16458,16459,16460,16461,16462,16463,16464,16465,
8174716466,16467,16468,16469,16470,16471,16472,16473,16474,16475,16476,16477,
8174816478,16479,16480,16481,16482,16483,16484,16485,16486,16487,16488,16489,
8174916490,16491,16492,16493,16494,16495,16496,16497,16498,16499,16500,16501,
8175016502,16503,16504,16505,16506,16507,16508,16509,16510,16511,16512,16513,
8175116514,16515,16516,16517,16518,16519,16520,16521,16522,16523,16524,16525,
8175216526,16527,16528,16529,16530,16531,16532,16533,16534,16535,16536,16537,
8175316538,16539,16540,16541,16542,16543,16544,16545,16546,16547,16548,16549,
8175416550,16551,16552,16553,16554,16555,16556,16557,16558,16559,16560,16561,
8175516562,16563,16564,16565,16566,16567,16568,16569,16570,16571,16572,16573,
8175616574,16575,16576,16577,16578,16579,16580,16581,16582,16583,16584,16585,
8175716586,16587,16588,16589,16590,16591,16592,16593,16594,16595,16596,16597,
8175816598,16599,16600,16601,16602,16603,16604,16605,16606,16607,16608,16609,
8175916610,16611,16612,16613,16614,16615,16616,16617,16618,16619,16620,16621,
8176016622,16623,16624,16625,16626,16627,16628,16629,16630,16631,16632,16633,
8176116634,16635,16636,16637,16638,16639,16640,16641,16642,16643,16644,16645,
8176216646,16647,16648,16649,16650,16651,16652,16653,16654,16655,16656,16657,
8176316658,16659,16660,16661,16662,16663,16664,16665,16666,16667,16668,16669,
8176416670,16671,16672,16673,16674,16675,16676,16677,16678,16679,16680,16681,
8176516682,16683,16684,16685,16686,16687,16688,16689,16690,16691,16692,16693,
8176616694,16695,16696,16697,16698,16699,16700,16701,16702,16703,16704,16705,
8176716706,16707,16708,16709,16710,16711,16712,16713,16714,16715,16716,16717,
8176816718,16719,16720,16721,16722,16723,16724,16725,16726,16727,16728,16729,
8176916730,16731,16732,16733,16734,16735,16736,16737,16738,16739,16740,16741,
8177016742,16743,16744,16745,16746,16747,16748,16749,16750,16751,16752,16753,
8177116754,16755,16756,16757,16758,16759,16760,16761,16762,16763,16764,16765,
8177216766,16767,16768,16769,16770,16771,16772,16773,16774,16775,16776,16777,
8177316778,16779,16780,16781,16782,16783,16784,16785,16786,16787,16788,16789,
8177416790,16791,16792,16793,16794,16795,16796,16797,16798,16799,16800,16801,
8177516802,16803,16804,16805,16806,16807,16808,16809,16810,16811,16812,16813,
8177616814,16815,16816,16817,16818,16819,16820,16821,16822,16823,16824,16825,
8177716826,16827,16828,16829,16830,16831,16832,16833,16834,16835,16836,16837,
8177816838,16839,16840,16841,16842,16843,16844,16845,16846,16847,16848,16849,
8177916850,16851,16852,16853,16854,16855,16856,16857,16858,16859,16860,16861,
8178016862,16863,16864,16865,16866,16867,16868,16869,16870,16871,16872,16873,
8178116874,16875,16876,16877,16878,16879,16880,16881,16882,16883,16884,16885,
8178216886,16887,16888,16889,16890,16891,16892,16893,16894,16895,16896,16897,
8178316898,16899,16900,16901,16902,16903,16904,16905,16906,16907,16908,16909,
8178416910,16911,16912,16913,16914,16915,16916,16917,16918,16919,16920,16921,
8178516922,16923,16924,16925,16926,16927,16928,16929,16930,16931,16932,16933,
8178616934,16935,16936,16937,16938,16939,16940,16941,16942,16943,16944,16945,
8178716946,16947,16948,16949,16950,16951,16952,16953,16954,16955,16956,16957,
8178816958,16959,16960,16961,16962,16963,16964,16965,16966,16967,16968,16969,
8178916970,16971,16972,16973,16974,16975,16976,16977,16978,16979,16980,16981,
8179016982,16983,16984,16985,16986,16987,16988,16989,16990,16991,16992,16993,
8179116994,16995,16996,16997,16998,16999,17000,17001,17002,17003,17004,17005,
8179217006,17007,17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,
8179317018,17019,17020,17021,17022,17023,17024,17025,17026,17027,17028,17029,
8179417030,17031,17032,17033,17034,17035,17036,17037,17038,17039,17040,17041,
8179517042,17043,17044,17045,17046,17047,17048,17049,17050,17051,17052,17053,
8179617054,17055,17056,17057,17058,17059,17060,17061,17062,17063,17064,17065,
8179717066,17067,17068,17069,17070,17071,17072,17073,17074,17075,17076,17077,
8179817078,17079,17080,17081,17082,17083,17084,17085,17086,17087,17088,17089,
8179917090,17091,17092,17093,17094,17095,17096,17097,17098,17099,17100,17101,
8180017102,17103,17104,17105,17106,17107,17108,17109,17110,17111,17112,17113,
8180117114,17115,17116,17117,17118,17119,17120,17121,17122,17123,17124,17125,
8180217126,17127,17128,17129,17130,17131,17132,17133,17134,17135,17136,17137,
8180317138,17139,17140,17141,17142,17143,17144,17145,17146,17147,17148,17149,
8180417150,17151,17152,17153,17154,17155,17156,17157,17158,17159,17160,17161,
8180517162,17163,17164,17165,17166,17167,17168,17169,17170,17171,17172,17173,
8180617174,17175,17176,17177,17178,17179,17180,17181,17182,17183,17184,17185,
8180717186,17187,17188,17189,17190,17191,17192,17193,17194,17195,17196,17197,
8180817198,17199,17200,17201,17202,17203,17204,17205,17206,17207,17208,17209,
8180917210,17211,17212,17213,17214,17215,17216,17217,17218,17219,17220,17221,
8181017222,17223,17224,17225,17226,17227,17228,17229,17230,17231,17232,17233,
8181117234,17235,17236,17237,17238,17239,17240,17241,17242,17243,17244,17245,
8181217246,17247,17248,17249,17250,17251,17252,17253,17254,17255,17256,17257,
8181317258,17259,17260,17261,17262,17263,17264,17265,17266,17267,17268,17269,
8181417270,17271,17272,17273,17274,17275,17276,17277,17278,17279,17280,17281,
8181517282,17283,17284,17285,17286,17287,17288,17289,17290,17291,17292,17293,
8181617294,17295,17296,17297,17298,17299,17300,17301,17302,17303,17304,17305,
8181717306,17307,17308,17309,17310,17311,17312,17313,17314,17315,17316,17317,
8181817318,17319,17320,17321,17322,17323,17324,17325,17326,17327,17328,17329,
8181917330,17331,17332,17333,17334,17335,17336,17337,17338,17339,17340,17341,
8182017342,17343,17344,17345,17346,17347,17348,17349,17350,17351,17352,17353,
8182117354,17355,17356,17357,17358,17359,17360,17361,17362,17363,17364,17365,
8182217366,17367,17368,17369,17370,17371,17372,17373,17374,17375,17376,17377,
8182317378,17379,17380,17381,17382,17383,17384,17385,17386,17387,17388,17389,
8182417390,17391,17392,17393,17394,17395,17396,17397,17398,17399,17400,17401,
8182517402,17403,17404,17405,17406,17407,17408,17409,17410,17411,17412,17413,
8182617414,17415,17416,17417,17418,17419,17420,17421,17422,17423,17424,17425,
8182717426,17427,17428,17429,17430,17431,17432,17433,17434,17435,17436,17437,
8182817438,17439,17440,17441,17442,17443,17444,17445,17446,17447,17448,17449,
8182917450,17451,17452,17453,17454,17455,17456,17457,17458,17459,17460,17461,
8183017462,17463,17464,17465,17466,17467,17468,17469,17470,17471,17472,17473,
8183117474,17475,17476,17477,17478,17479,17480,17481,17482,17483,17484,17485,
8183217486,17487,17488,17489,17490,17491,17492,17493,17494,17495,17496,17497,
8183317498,17499,17500,17501,17502,17503,17504,17505,17506,17507,17508,17509,
8183417510,17511,17512,17513,17514,17515,17516,17517,17518,17519,17520,17521,
8183517522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,
8183617534,17535,17536,17537,17538,17539,17540,17541,17542,17543,17544,17545,
8183717546,17547,17548,17549,17550,17551,17552,17553,17554,17555,17556,17557,
8183817558,17559,17560,17561,17562,17563,17564,17565,17566,17567,17568,17569,
8183917570,17571,17572,17573,17574,17575,17576,17577,17578,17579,17580,17581,
8184017582,17583,17584,17585,17586,17587,17588,17589,17590,17591,17592,17593,
8184117594,17595,17596,17597,17598,17599,17600,17601,17602,17603,17604,17605,
8184217606,17607,17608,17609,17610,17611,17612,17613,17614,17615,17616,17617,
8184317618,17619,17620,17621,17622,17623,17624,17625,17626,17627,17628,17629,
8184417630,17631,17632,17633,17634,17635,17636,17637,17638,17639,17640,17641,
8184517642,17643,17644,17645,17646,17647,17648,17649,17650,17651,17652,17653,
8184617654,17655,17656,17657,17658,17659,17660,17661,17662,17663,17664,17665,
8184717666,17667,17668,17669,17670,17671,17672,17673,17674,17675,17676,17677,
8184817678,17679,17680,17681,17682,17683,17684,17685,17686,17687,17688,17689,
8184917690,17691,17692,17693,17694,17695,17696,17697,17698,17699,17700,17701,
8185017702,17703,17704,17705,17706,17707,17708,17709,17710,17711,17712,17713,
8185117714,17715,17716,17717,17718,17719,17720,17721,17722,17723,17724,17725,
8185217726,17727,17728,17729,17730,17731,17732,17733,17734,17735,17736,17737,
8185317738,17739,17740,17741,17742,17743,17744,17745,17746,17747,17748,17749,
8185417750,17751,17752,17753,17754,17755,17756,17757,17758,17759,17760,17761,
8185517762,17763,17764,17765,17766,17767,17768,17769,17770,17771,17772,17773,
8185617774,17775,17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,
8185717786,17787,17788,17789,17790,17791,17792,17793,17794,17795,17796,17797,
8185817798,17799,17800,17801,17802,17803,17804,17805,17806,17807,17808,17809,
8185917810,17811,17812,17813,17814,17815,17816,17817,17818,17819,17820,17821,
8186017822,17823,17824,17825,17826,17827,17828,17829,17830,17831,17832,17833,
8186117834,17835,17836,17837,17838,17839,17840,17841,17842,17843,17844,17845,
8186217846,17847,17848,17849,17850,17851,17852,17853,17854,17855,17856,17857,
8186317858,17859,17860,17861,17862,17863,17864,17865,17866,17867,17868,17869,
8186417870,17871,17872,17873,17874,17875,17876,17877,17878,17879,17880,17881,
8186517882,17883,17884,17885,17886,17887,17888,17889,17890,17891,17892,17893,
8186617894,17895,17896,17897,17898,17899,17900,17901,17902,17903,17904,17905,
8186717906,17907,17908,17909,17910,17911,17912,17913,17914,17915,17916,17917,
8186817918,17919,17920,17921,17922,17923,17924,17925,17926,17927,17928,17929,
8186917930,17931,17932,17933,17934,17935,17936,17937,17938,17939,17940,17941,
8187017942,17943,17944,17945,17946,17947,17948,17949,17950,17951,17952,17953,
8187117954,17955,17956,17957,17958,17959,17960,17961,17962,17963,17964,17965,
8187217966,17967,17968,17969,17970,17971,17972,17973,17974,17975,17976,17977,
8187317978,17979,17980,17981,17982,17983,17984,17985,17986,17987,17988,17989,
8187417990,17991,17992,17993,17994,17995,17996,17997,17998,17999,18000,18001,
8187518002,18003,18004,18005,18006,18007,18008,18009,18010,18011,18012,18013,
8187618014,18015,18016,18017,18018,18019,18020,18021,18022,18023,18024,18025,
8187718026,18027,18028,18029,18030,18031,18032,18033,18034,18035,18036,18037,
8187818038,18039,18040,18041,18042,18043,18044,18045,18046,18047,18048,18049,
8187918050,18051,18052,18053,18054,18055,18056,18057,18058,18059,18060,18061,
8188018062,18063,18064,18065,18066,18067,18068,18069,18070,18071,18072,18073,
8188118074,18075,18076,18077,18078,18079,18080,18081,18082,18083,18084,18085,
8188218086,18087,18088,18089,18090,18091,18092,18093,18094,18095,18096,18097,
8188318098,18099,18100,18101,18102,18103,18104,18105,18106,18107,18108,18109,
8188418110,18111,18112,18113,18114,18115,18116,18117,18118,18119,18120,18121,
8188518122,18123,18124,18125,18126,18127,18128,18129,18130,18131,18132,18133,
8188618134,18135,18136,18137,18138,18139,18140,18141,18142,18143,18144,18145,
8188718146,18147,18148,18149,18150,18151,18152,18153,18154,18155,18156,18157,
8188818158,18159,18160,18161,18162,18163,18164,18165,18166,18167,18168,18169,
8188918170,18171,18172,18173,18174,18175,18176,18177,18178,18179,18180,18181,
8189018182,18183,18184,18185,18186,18187,18188,18189,18190,18191,18192,18193,
8189118194,18195,18196,18197,18198,18199,18200,18201,18202,18203,18204,18205,
8189218206,18207,18208,18209,18210,18211,18212,18213,18214,18215,18216,18217,
8189318218,18219,18220,18221,18222,18223,18224,18225,18226,18227,18228,18229,
8189418230,18231,18232,18233,18234,18235,18236,18237,18238,18239,18240,18241,
8189518242,18243,18244,18245,18246,18247,18248,18249,18250,18251,18252,18253,
8189618254,18255,18256,18257,18258,18259,18260,18261,18262,18263,18264,18265,
8189718266,18267,18268,18269,18270,18271,18272,18273,18274,18275,18276,18277,
8189818278,18279,18280,18281,18282,18283,18284,18285,18286,18287,18288,18289,
8189918290,18291,18292,18293,18294,18295,18296,18297,18298,18299,18300,18301,
8190018302,18303,18304,18305,18306,18307,18308,18309,18310,18311,18312,18313,
8190118314,18315,18316,18317,18318,18319,18320,18321,18322,18323,18324,18325,
8190218326,18327,18328,18329,18330,18331,18332,18333,18334,18335,18336,18337,
8190318338,18339,18340,18341,18342,18343,18344,18345,18346,18347,18348,18349,
8190418350,18351,18352,18353,18354,18355,18356,18357,18358,18359,18360,18361,
8190518362,18363,18364,18365,18366,18367,18368,18369,18370,18371,18372,18373,
8190618374,18375,18376,18377,18378,18379,18380,18381,18382,18383,18384,18385,
8190718386,18387,18388,18389,18390,18391,18392,18393,18394,18395,18396,18397,
8190818398,18399,18400,18401,18402,18403,18404,18405,18406,18407,18408,18409,
8190918410,18411,18412,18413,18414,18415,18416,18417,18418,18419,18420,18421,
8191018422,18423,18424,18425,18426,18427,18428,18429,18430,18431,18432,18433,
8191118434,18435,18436,18437,18438,18439,18440,18441,18442,18443,18444,18445,
8191218446,18447,18448,18449,18450,18451,18452,18453,18454,18455,18456,18457,
8191318458,18459,18460,18461,18462,18463,18464,18465,18466,18467,18468,18469,
8191418470,18471,18472,18473,18474,18475,18476,18477,18478,18479,18480,18481,
8191518482,18483,18484,18485,18486,18487,18488,18489,18490,18491,18492,18493,
8191618494,18495,18496,18497,18498,18499,18500,18501,18502,18503,18504,18505,
8191718506,18507,18508,18509,18510,18511,18512,18513,18514,18515,18516,18517,
8191818518,18519,18520,18521,18522,18523,18524,18525,18526,18527,18528,18529,
8191918530,18531,18532,18533,18534,18535,18536,18537,18538,18539,18540,18541,
8192018542,18543,18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,
8192118554,18555,18556,18557,18558,18559,18560,18561,18562,18563,18564,18565,
8192218566,18567,18568,18569,18570,18571,18572,18573,18574,18575,18576,18577,
8192318578,18579,18580,18581,18582,18583,18584,18585,18586,18587,18588,18589,
8192418590,18591,18592,18593,18594,18595,18596,18597,18598,18599,18600,18601,
8192518602,18603,18604,18605,18606,18607,18608,18609,18610,18611,18612,18613,
8192618614,18615,18616,18617,18618,18619,18620,18621,18622,18623,18624,18625,
8192718626,18627,18628,18629,18630,18631,18632,18633,18634,18635,18636,18637,
8192818638,18639,18640,18641,18642,18643,18644,18645,18646,18647,18648,18649,
8192918650,18651,18652,18653,18654,18655,18656,18657,18658,18659,18660,18661,
8193018662,18663,18664,18665,18666,18667,18668,18669,18670,18671,18672,18673,
8193118674,18675,18676,18677,18678,18679,18680,18681,18682,18683,18684,18685,
8193218686,18687,18688,18689,18690,18691,18692,18693,18694,18695,18696,18697,
8193318698,18699,18700,18701,18702,18703,18704,18705,18706,18707,18708,18709,
8193418710,18711,18712,18713,18714,18715,18716,18717,18718,18719,18720,18721,
8193518722,18723,18724,18725,18726,18727,18728,18729,18730,18731,18732,18733,
8193618734,18735,18736,18737,18738,18739,18740,18741,18742,18743,18744,18745,
8193718746,18747,18748,18749,18750,18751,18752,18753,18754,18755,18756,18757,
8193818758,18759,18760,18761,18762,18763,18764,18765,18766,18767,18768,18769,
8193918770,18771,18772,18773,18774,18775,18776,18777,18778,18779,18780,18781,
8194018782,18783,18784,18785,18786,18787,18788,18789,18790,18791,18792,18793,
8194118794,18795,18796,18797,18798,18799,18800,18801,18802,18803,18804,18805,
8194218806,18807,18808,18809,18810,18811,18812,18813,18814,18815,18816,18817,
8194318818,18819,18820,18821,18822,18823,18824,18825,18826,18827,18828,18829,
8194418830,18831,18832,18833,18834,18835,18836,18837,18838,18839,18840,18841,
8194518842,18843,18844,18845,18846,18847,18848,18849,18850,18851,18852,18853,
8194618854,18855,18856,18857,18858,18859,18860,18861,18862,18863,18864,18865,
8194718866,18867,18868,18869,18870,18871,18872,18873,18874,18875,18876,18877,
8194818878,18879,18880,18881,18882,18883,18884,18885,18886,18887,18888,18889,
8194918890,18891,18892,18893,18894,18895,18896,18897,18898,18899,18900,18901,
8195018902,18903,18904,18905,18906,18907,18908,18909,18910,18911,18912,18913,
8195118914,18915,18916,18917,18918,18919,18920,18921,18922,18923,18924,18925,
8195218926,18927,18928,18929,18930,18931,18932,18933,18934,18935,18936,18937,
8195318938,18939,18940,18941,18942,18943,18944,18945,18946,18947,18948,18949,
8195418950,18951,18952,18953,18954,18955,18956,18957,18958,18959,18960,18961,
8195518962,18963,18964,18965,18966,18967,18968,18969,18970,18971,18972,18973,
8195618974,18975,18976,18977,18978,18979,18980,18981,18982,18983,18984,18985,
8195718986,18987,18988,18989,18990,18991,18992,18993,18994,18995,18996,18997,
8195818998,18999,19000,19001,19002,19003,19004,19005,19006,19007,19008,19009,
8195919010,19011,19012,19013,19014,19015,19016,19017,19018,19019,19020,19021,
8196019022,19023,19024,19025,19026,19027,19028,19029,19030,19031,19032,19033,
8196119034,19035,19036,19037,19038,19039,19040,19041,19042,19043,19044,19045,
8196219046,19047,19048,19049,19050,19051,19052,19053,19054,19055,19056,19057,
8196319058,19059,19060,19061,19062,19063,19064,19065,19066,19067,19068,19069,
8196419070,19071,19072,19073,19074,19075,19076,19077,19078,19079,19080,19081,
8196519082,19083,19084,19085,19086,19087,19088,19089,19090,19091,19092,19093,
8196619094,19095,19096,19097,19098,19099,19100,19101,19102,19103,19104,19105,
8196719106,19107,19108,19109,19110,19111,19112,19113,19114,19115,19116,19117,
8196819118,19119,19120,19121,19122,19123,19124,19125,19126,19127,19128,19129,
8196919130,19131,19132,19133,19134,19135,19136,19137,19138,19139,19140,19141,
8197019142,19143,19144,19145,19146,19147,19148,19149,19150,19151,19152,19153,
8197119154,19155,19156,19157,19158,19159,19160,19161,19162,19163,19164,19165,
8197219166,19167,19168,19169,19170,19171,19172,19173,19174,19175,19176,19177,
8197319178,19179,19180,19181,19182,19183,19184,19185,19186,19187,19188,19189,
8197419190,19191,19192,19193,19194,19195,19196,19197,19198,19199,19200,19201,
8197519202,19203,19204,19205,19206,19207,19208,19209,19210,19211,19212,19213,
8197619214,19215,19216,19217,19218,19219,19220,19221,19222,19223,19224,19225,
8197719226,19227,19228,19229,19230,19231,19232,19233,19234,19235,19236,19237,
8197819238,19239,19240,19241,19242,19243,19244,19245,19246,19247,19248,19249,
8197919250,19251,19252,19253,19254,19255,19256,19257,19258,19259,19260,19261,
8198019262,19263,19264,19265,19266,19267,19268,19269,19270,19271,19272,19273,
8198119274,19275,19276,19277,19278,19279,19280,19281,19282,19283,19284,19285,
8198219286,19287,19288,19289,19290,19291,19292,19293,19294,19295,19296,19297,
8198319298,19299,19300,19301,19302,19303,19304,19305,19306,19307,19308,19309,
8198419310,19311,19312,19313,19314,19315,19316,19317,19318,19319,19320,19321,
8198519322,19323,19324,19325,19326,19327,19328,19329,19330,19331,19332,19333,
8198619334,19335,19336,19337,19338,19339,19340,19341,19342,19343,19344,19345,
8198719346,19347,19348,19349,19350,19351,19352,19353,19354,19355,19356,19357,
8198819358,19359,19360,19361,19362,19363,19364,19365,19366,19367,19368,19369,
8198919370,19371,19372,19373,19374,19375,19376,19377,19378,19379,19380,19381,
8199019382,19383,19384,19385,19386,19387,19388,19389,19390,19391,19392,19393,
8199119394,19395,19396,19397,19398,19399,19400,19401,19402,19403,19404,19405,
8199219406,19407,19408,19409,19410,19411,19412,19413,19414,19415,19416,19417,
8199319418,19419,19420,19421,19422,19423,19424,19425,19426,19427,19428,19429,
8199419430,19431,19432,19433,19434,19435,19436,19437,19438,19439,19440,19441,
8199519442,19443,19444,19445,19446,19447,19448,19449,19450,19451,19452,19453,
8199619454,19455,19456,19457,19458,19459,19460,19461,19462,19463,19464,19465,
8199719466,19467,19468,19469,19470,19471,19472,19473,19474,19475,19476,19477,
8199819478,19479,19480,19481,19482,19483,19484,19485,19486,19487,19488,19489,
8199919490,19491,19492,19493,19494,19495,19496,19497,19498,19499,19500,19501,
8200019502,19503,19504,19505,19506,19507,19508,19509,19510,19511,19512,19513,
8200119514,19515,19516,19517,19518,19519,19520,19521,19522,19523,19524,19525,
8200219526,19527,19528,19529,19530,19531,19532,19533,19534,19535,19536,19537,
8200319538,19539,19540,19541,19542,19543,19544,19545,19546,19547,19548,19549,
8200419550,19551,19552,19553,19554,19555,19556,19557,19558,19559,19560,19561,
8200519562,19563,19564,19565,19566,19567,19568,19569,19570,19571,19572,19573,
8200619574,19575,19576,19577,19578,19579,19580,19581,19582,19583,19584,19585,
8200719586,19587,19588,19589,19590,19591,19592,19593,19594,19595,19596,19597,
8200819598,19599,19600,19601,19602,19603,19604,19605,19606,19607,19608,19609,
8200919610,19611,19612,19613,19614,19615,19616,19617,19618,19619,19620,19621,
8201019622,19623,19624,19625,19626,19627,19628,19629,19630,19631,19632,19633,
8201119634,19635,19636,19637,19638,19639,19640,19641,19642,19643,19644,19645,
8201219646,19647,19648,19649,19650,19651,19652,19653,19654,19655,19656,19657,
8201319658,19659,19660,19661,19662,19663,19664,19665,19666,19667,19668,19669,
8201419670,19671,19672,19673,19674,19675,19676,19677,19678,19679,19680,19681,
8201519682,19683,19684,19685,19686,19687,19688,19689,19690,19691,19692,19693,
8201619694,19695,19696,19697,19698,19699,19700,19701,19702,19703,19704,19705,
8201719706,19707,19708,19709,19710,19711,19712,19713,19714,19715,19716,19717,
8201819718,19719,19720,19721,19722,19723,19724,19725,19726,19727,19728,19729,
8201919730,19731,19732,19733,19734,19735,19736,19737,19738,19739,19740,19741,
8202019742,19743,19744,19745,19746,19747,19748,19749,19750,19751,19752,19753,
8202119754,19755,19756,19757,19758,19759,19760,19761,19762,19763,19764,19765,
8202219766,19767,19768,19769,19770,19771,19772,19773,19774,19775,19776,19777,
8202319778,19779,19780,19781,19782,19783,19784,19785,19786,19787,19788,19789,
8202419790,19791,19792,19793,19794,19795,19796,19797,19798,19799,19800,19801,
8202519802,19803,19804,19805,19806,19807,19808,19809,19810,19811,19812,19813,
8202619814,19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825,
8202719826,19827,19828,19829,19830,19831,19832,19833,19834,19835,19836,19837,
8202819838,19839,19840,19841,19842,19843,19844,19845,19846,19847,19848,19849,
8202919850,19851,19852,19853,19854,19855,19856,19857,19858,19859,19860,19861,
8203019862,19863,19864,19865,19866,19867,19868,19869,19870,19871,19872,19873,
8203119874,19875,19876,19877,19878,19879,19880,19881,19882,19883,19884,19885,
8203219886,19887,19888,19889,19890,19891,19892,19893,19894,19895,19896,19897,
8203319898,19899,19900,19901,19902,19903,19904,19905,19906,19907,19908,19909,
8203419910,19911,19912,19913,19914,19915,19916,19917,19918,19919,19920,19921,
8203519922,19923,19924,19925,19926,19927,19928,19929,19930,19931,19932,19933,
8203619934,19935,19936,19937,19938,19939,19940,19941,19942,19943,19944,19945,
8203719946,19947,19948,19949,19950,19951,19952,19953,19954,19955,19956,19957,
8203819958,19959,19960,19961,19962,19963,19964,19965,19966,19967,19968,19969,
8203919970,19971,19972,19973,19974,19975,19976,19977,19978,19979,19980,19981,
8204019982,19983,19984,19985,19986,19987,19988,19989,19990,19991,19992,19993,
8204119994,19995,19996,19997,19998,19999,20000,20001,20002,20003,20004,20005,
8204220006,20007,20008,20009,20010,20011,20012,20013,20014,20015,20016,20017,
8204320018,20019,20020,20021,20022,20023,20024,20025,20026,20027,20028,20029,
8204420030,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,20041,
8204520042,20043,20044,20045,20046,20047,20048,20049,20050,20051,20052,20053,
8204620054,20055,20056,20057,20058,20059,20060,20061,20062,20063,20064,20065,
8204720066,20067,20068,20069,20070,20071,20072,20073,20074,20075,20076,20077,
8204820078,20079,20080,20081,20082,20083,20084,20085,20086,20087,20088,20089,
8204920090,20091,20092,20093,20094,20095,20096,20097,20098,20099,20100,20101,
8205020102,20103,20104,20105,20106,20107,20108,20109,20110,20111,20112,20113,
8205120114,20115,20116,20117,20118,20119,20120,20121,20122,20123,20124,20125,
8205220126,20127,20128,20129,20130,20131,20132,20133,20134,20135,20136,20137,
8205320138,20139,20140,20141,20142,20143,20144,20145,20146,20147,20148,20149,
8205420150,20151,20152,20153,20154,20155,20156,20157,20158,20159,20160,20161,
8205520162,20163,20164,20165,20166,20167,20168,20169,20170,20171,20172,20173,
8205620174,20175,20176,20177,20178,20179,20180,20181,20182,20183,20184,20185,
8205720186,20187,20188,20189,20190,20191,20192,20193,20194,20195,20196,20197,
8205820198,20199,20200,20201,20202,20203,20204,20205,20206,20207,20208,20209,
8205920210,20211,20212,20213,20214,20215,20216,20217,20218,20219,20220,20221,
8206020222,20223,20224,20225,20226,20227,20228,20229,20230,20231,20232,20233,
8206120234,20235,20236,20237,20238,20239,20240,20241,20242,20243,20244,20245,
8206220246,20247,20248,20249,20250,20251,20252,20253,20254,20255,20256,20257,
8206320258,20259,20260,20261,20262,20263,20264,20265,20266,20267,20268,20269,
8206420270,20271,20272,20273,20274,20275,20276,20277,20278,20279,20280,20281,
8206520282,20283,20284,20285,20286,20287,20288,20289,20290,20291,20292,20293,
8206620294,20295,20296,20297,20298,20299,20300,20301,20302,20303,20304,20305,
8206720306,20307,20308,20309,20310,20311,20312,20313,20314,20315,20316,20317,
8206820318,20319,20320,20321,20322,20323,20324,20325,20326,20327,20328,20329,
8206920330,20331,20332,20333,20334,20335,20336,20337,20338,20339,20340,20341,
8207020342,20343,20344,20345,20346,20347,20348,20349,20350,20351,20352,20353,
8207120354,20355,20356,20357,20358,20359,20360,20361,20362,20363,20364,20365,
8207220366,20367,20368,20369,20370,20371,20372,20373,20374,20375,20376,20377,
8207320378,20379,20380,20381,20382,20383,20384,20385,20386,20387,20388,20389,
8207420390,20391,20392,20393,20394,20395,20396,20397,20398,20399,20400,20401,
8207520402,20403,20404,20405,20406,20407,20408,20409,20410,20411,20412,20413,
8207620414,20415,20416,20417,20418,20419,20420,20421,20422,20423,20424,20425,
8207720426,20427,20428,20429,20430,20431,20432,20433,20434,20435,20436,20437,
8207820438,20439,20440,20441,20442,20443,20444,20445,20446,20447,20448,20449,
8207920450,20451,20452,20453,20454,20455,20456,20457,20458,20459,20460,20461,
8208020462,20463,20464,20465,20466,20467,20468,20469,20470,20471,20472,20473,
8208120474,20475,20476,20477,20478,20479,20480,20481,20482,20483,20484,20485,
8208220486,20487,20488,20489,20490,20491,20492,20493,20494,20495,20496,20497,
8208320498,20499,20500,20501,20502,20503,20504,20505,20506,20507,20508,20509,
8208420510,20511,20512,20513,20514,20515,20516,20517,20518,20519,20520,20521,
8208520522,20523,20524,20525,20526,20527,20528,20529,20530,20531,20532,20533,
8208620534,20535,20536,20537,20538,20539,20540,20541,20542,20543,20544,20545,
8208720546,20547,20548,20549,20550,20551,20552,20553,20554,20555,20556,20557,
8208820558,20559,20560,20561,20562,20563,20564,20565,20566,20567,20568,20569,
8208920570,20571,20572,20573,20574,20575,20576,20577,20578,20579,20580,20581,
8209020582,20583,20584,20585,20586,20587,20588,20589,20590,20591,20592,20593,
8209120594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,20605,
8209220606,20607,20608,20609,20610,20611,20612,20613,20614,20615,20616,20617,
8209320618,20619,20620,20621,20622,20623,20624,20625,20626,20627,20628,20629,
8209420630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,
8209520642,20643,20644,20645,20646,20647,20648,20649,20650,20651,20652,20653,
8209620654,20655,20656,20657,20658,20659,20660,20661,20662,20663,20664,20665,
8209720666,20667,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,
8209820678,20679,20680,20681,20682,20683,20684,20685,20686,20687,20688,20689,
8209920690,20691,20692,20693,20694,20695,20696,20697,20698,20699,20700,20701,
8210020702,20703,20704,20705,20706,20707,20708,20709,20710,20711,20712,20713,
8210120714,20715,20716,20717,20718,20719,20720,20721,20722,20723,20724,20725,
8210220726,20727,20728,20729,20730,20731,20732,20733,20734,20735,20736,20737,
8210320738,20739,20740,20741,20742,20743,20744,20745,20746,20747,20748,20749,
8210420750,20751,20752,20753,20754,20755,20756,20757,20758,20759,20760,20761,
8210520762,20763,20764,20765,20766,20767,20768,20769,20770,20771,20772,20773,
8210620774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,
8210720786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,
8210820798,20799,20800,20801,20802,20803,20804,20805,20806,20807,20808,20809,
8210920810,20811,20812,20813,20814,20815,20816,20817,20818,20819,20820,20821,
8211020822,20823,20824,20825,20826,20827,20828,20829,20830,20831,20832,20833,
8211120834,20835,20836,20837,20838,20839,20840,20841,20842,20843,20844,20845,
8211220846,20847,20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,
8211320858,20859,20860,20861,20862,20863,20864,20865,20866,20867,20868,20869,
8211420870,20871,20872,20873,20874,20875,20876,20877,20878,20879,20880,20881,
8211520882,20883,20884,20885,20886,20887,20888,20889,20890,20891,20892,20893,
8211620894,20895,20896,20897,20898,20899,20900,20901,20902,20903,20904,20905,
8211720906,20907,20908,20909,20910,20911,20912,20913,20914,20915,20916,20917,
8211820918,20919,20920,20921,20922,20923,20924,20925,20926,20927,20928,20929,
8211920930,20931,20932,20933,20934,20935,20936,20937,20938,20939,20940,20941,
8212020942,20943,20944,20945,20946,20947,20948,20949,20950,20951,20952,20953,
8212120954,20955,20956,20957,20958,20959,20960,20961,20962,20963,20964,20965,
8212220966,20967,20968,20969,20970,20971,20972,20973,20974,20975,20976,20977,
8212320978,20979,20980,20981,20982,20983,20984,20985,20986,20987,20988,20989,
8212420990,20991,20992,20993,20994,20995,20996,20997,20998,20999,21000,21001,
8212521002,21003,21004,21005,21006,21007,21008,21009,21010,21011,21012,21013,
8212621014,21015,21016,21017,21018,21019,21020,21021,21022,21023,21024,21025,
8212721026,21027,21028,21029,21030,21031,21032,21033,21034,21035,21036,21037,
8212821038,21039,21040,21041,21042,21043,21044,21045,21046,21047,21048,21049,
8212921050,21051,21052,21053,21054,21055,21056,21057,21058,21059,21060,21061,
8213021062,21063,21064,21065,21066,21067,21068,21069,21070,21071,21072,21073,
8213121074,21075,21076,21077,21078,21079,21080,21081,21082,21083,21084,21085,
8213221086,21087,21088,21089,21090,21091,21092,21093,21094,21095,21096,21097,
8213321098,21099,21100,21101,21102,21103,21104,21105,21106,21107,21108,21109,
8213421110,21111,21112,21113,21114,21115,21116,21117,21118,21119,21120,21121,
8213521122,21123,21124,21125,21126,21127,21128,21129,21130,21131,21132,21133,
8213621134,21135,21136,21137,21138,21139,21140,21141,21142,21143,21144,21145,
8213721146,21147,21148,21149,21150,21151,21152,21153,21154,21155,21156,21157,
8213821158,21159,21160,21161,21162,21163,21164,21165,21166,21167,21168,21169,
8213921170,21171,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,
8214021182,21183,21184,21185,21186,21187,21188,21189,21190,21191,21192,21193,
8214121194,21195,21196,21197,21198,21199,21200,21201,21202,21203,21204,21205,
8214221206,21207,21208,21209,21210,21211,21212,21213,21214,21215,21216,21217,
8214321218,21219,21220,21221,21222,21223,21224,21225,21226,21227,21228,21229,
8214421230,21231,21232,21233,21234,21235,21236,21237,21238,21239,21240,21241,
8214521242,21243,21244,21245,21246,21247,21248,21249,21250,21251,21252,21253,
8214621254,21255,21256,21257,21258,21259,21260,21261,21262,21263,21264,21265,
8214721266,21267,21268,21269,21270,21271,21272,21273,21274,21275,21276,21277,
8214821278,21279,21280,21281,21282,21283,21284,21285,21286,21287,21288,21289,
8214921290,21291,21292,21293,21294,21295,21296,21297,21298,21299,21300,21301,
8215021302,21303,21304,21305,21306,21307,21308,21309,21310,21311,21312,21313,
8215121314,21315,21316,21317,21318,21319,21320,21321,21322,21323,21324,21325,
8215221326,21327,21328,21329,21330,21331,21332,21333,21334,21335,21336,21337,
8215321338,21339,21340,21341,21342,21343,21344,21345,21346,21347,21348,21349,
8215421350,21351,21352,21353,21354,21355,21356,21357,21358,21359,21360,21361,
8215521362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,
8215621374,21375,21376,21377,21378,21379,21380,21381,21382,21383,21384,21385,
8215721386,21387,21388,21389,21390,21391,21392,21393,21394,21395,21396,21397,
8215821398,21399,21400,21401,21402,21403,21404,21405,21406,21407,21408,21409,
8215921410,21411,21412,21413,21414,21415,21416,21417,21418,21419,21420,21421,
8216021422,21423,21424,21425,21426,21427,21428,21429,21430,21431,21432,21433,
8216121434,21435,21436,21437,21438,21439,21440,21441,21442,21443,21444,21445,
8216221446,21447,21448,21449,21450,21451,21452,21453,21454,21455,21456,21457,
8216321458,21459,21460,21461,21462,21463,21464,21465,21466,21467,21468,21469,
8216421470,21471,21472,21473,21474,21475,21476,21477,21478,21479,21480,21481,
8216521482,21483,21484,21485,21486,21487,21488,21489,21490,21491,21492,21493,
8216621494,21495,21496,21497,21498,21499,21500,21501,21502,21503,21504,21505,
8216721506,21507,21508,21509,21510,21511,21512,21513,21514,21515,21516,21517,
8216821518,21519,21520,21521,21522,21523,21524,21525,21526,21527,21528,21529,
8216921530,21531,21532,21533,21534,21535,21536,21537,21538,21539,21540,21541,
8217021542,21543,21544,21545,21546,21547,21548,21549,21550,21551,21552,21553,
8217121554,21555,21556,21557,21558,21559,21560,21561,21562,21563,21564,21565,
8217221566,21567,21568,21569,21570,21571,21572,21573,21574,21575,21576,21577,
8217321578,21579,21580,21581,21582,21583,21584,21585,21586,21587,21588,21589,
8217421590,21591,21592,21593,21594,21595,21596,21597,21598,21599,21600,21601,
8217521602,21603,21604,21605,21606,21607,21608,21609,21610,21611,21612,21613,
8217621614,21615,21616,21617,21618,21619,21620,21621,21622,21623,21624,21625,
8217721626,21627,21628,21629,21630,21631,21632,21633,21634,21635,21636,21637,
8217821638,21639,21640,21641,21642,21643,21644,21645,21646,21647,21648,21649,
8217921650,21651,21652,21653,21654,21655,21656,21657,21658,21659,21660,21661,
8218021662,21663,21664,21665,21666,21667,21668,21669,21670,21671,21672,21673,
8218121674,21675,21676,21677,21678,21679,21680,21681,21682,21683,21684,21685,
8218221686,21687,21688,21689,21690,21691,21692,21693,21694,21695,21696,21697,
8218321698,21699,21700,21701,21702,21703,21704,21705,21706,21707,21708,21709,
8218421710,21711,21712,21713,21714,21715,21716,21717,21718,21719,21720,21721,
8218521722,21723,21724,21725,21726,21727,21728,21729,21730,21731,21732,21733,
8218621734,21735,21736,21737,21738,21739,21740,21741,21742,21743,21744,21745,
8218721746,21747,21748,21749,21750,21751,21752,21753,21754,21755,21756,21757,
8218821758,21759,21760,21761,21762,21763,21764,21765,21766,21767,21768,21769,
8218921770,21771,21772,21773,21774,21775,21776,21777,21778,21779,21780,21781,
8219021782,21783,21784,21785,21786,21787,21788,21789,21790,21791,21792,21793,
8219121794,21795,21796,21797,21798,21799,21800,21801,21802,21803,21804,21805,
8219221806,21807,21808,21809,21810,21811,21812,21813,21814,21815,21816,21817,
8219321818,21819,21820,21821,21822,21823,21824,21825,21826,21827,21828,21829,
8219421830,21831,21832,21833,21834,21835,21836,21837,21838,21839,21840,21841,
8219521842,21843,21844,21845,21846,21847,21848,21849,21850,21851,21852,21853,
8219621854,21855,21856,21857,21858,21859,21860,21861,21862,21863,21864,21865,
8219721866,21867,21868,21869,21870,21871,21872,21873,21874,21875,21876,21877,
8219821878,21879,21880,21881,21882,21883,21884,21885,21886,21887,21888,21889,
8219921890,21891,21892,21893,21894,21895,21896,21897,21898,21899,21900,21901,
8220021902,21903,21904,21905,21906,21907,21908,21909,21910,21911,21912,21913,
8220121914,21915,21916,21917,21918,21919,21920,21921,21922,21923,21924,21925,
8220221926,21927,21928,21929,21930,21931,21932,21933,21934,21935,21936,21937,
8220321938,21939,21940,21941,21942,21943,21944,21945,21946,21947,21948,21949,
8220421950,21951,21952,21953,21954,21955,21956,21957,21958,21959,21960,21961,
8220521962,21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,21973,
8220621974,21975,21976,21977,21978,21979,21980,21981,21982,21983,21984,21985,
8220721986,21987,21988,21989,21990,21991,21992,21993,21994,21995,21996,21997,
8220821998,21999,22000,22001,22002,22003,22004,22005,22006,22007,22008,22009,
8220922010,22011,22012,22013,22014,22015,22016,22017,22018,22019,22020,22021,
8221022022,22023,22024,22025,22026,22027,22028,22029,22030,22031,22032,22033,
8221122034,22035,22036,22037,22038,22039,22040,22041,22042,22043,22044,22045,
8221222046,22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,22057,
8221322058,22059,22060,22061,22062,22063,22064,22065,22066,22067,22068,22069,
8221422070,22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,22081,
8221522082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22092,22093,
8221622094,22095,22096,22097,22098,22099,22100,22101,22102,22103,22104,22105,
8221722106,22107,22108,22109,22110,22111,22112,22113,22114,22115,22116,22117,
8221822118,22119,22120,22121,22122,22123,22124,22125,22126,22127,22128,22129,
8221922130,22131,22132,22133,22134,22135,22136,22137,22138,22139,22140,22141,
8222022142,22143,22144,22145,22146,22147,22148,22149,22150,22151,22152,22153,
8222122154,22155,22156,22157,22158,22159,22160,22161,22162,22163,22164,22165,
8222222166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,
8222322178,22179,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,
8222422190,22191,22192,22193,22194,22195,22196,22197,22198,22199,22200,22201,
8222522202,22203,22204,22205,22206,22207,22208,22209,22210,22211,22212,22213,
8222622214,22215,22216,22217,22218,22219,22220,22221,22222,22223,22224,22225,
8222722226,22227,22228,22229,22230,22231,22232,22233,22234,22235,22236,22237,
8222822238,22239,22240,22241,22242,22243,22244,22245,22246,22247,22248,22249,
8222922250,22251,22252,22253,22254,22255,22256,22257,22258,22259,22260,22261,
8223022262,22263,22264,22265,22266,22267,22268,22269,22270,22271,22272,22273,
8223122274,22275,22276,22277,22278,22279,22280,22281,22282,22283,22284,22285,
8223222286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,
8223322298,22299,22300,22301,22302,22303,22304,22305,22306,22307,22308,22309,
8223422310,22311,22312,22313,22314,22315,22316,22317,22318,22319,22320,22321,
8223522322,22323,22324,22325,22326,22327,22328,22329,22330,22331,22332,22333,
8223622334,22335,22336,22337,22338,22339,22340,22341,22342,22343,22344,22345,
8223722346,22347,22348,22349,22350,22351,22352,22353,22354,22355,22356,22357,
8223822358,22359,22360,22361,22362,22363,22364,22365,22366,22367,22368,22369,
8223922370,22371,22372,22373,22374,22375,22376,22377,22378,22379,22380,22381,
8224022382,22383,22384,22385,22386,22387,22388,22389,22390,22391,22392,22393,
8224122394,22395,22396,22397,22398,22399,22400,22401,22402,22403,22404,22405,
8224222406,22407,22408,22409,22410,22411,22412,22413,22414,22415,22416,22417,
8224322418,22419,22420,22421,22422,22423,22424,22425,22426,22427,22428,22429,
8224422430,22431,22432,22433,22434,22435,22436,22437,22438,22439,22440,22441,
8224522442,22443,22444,22445,22446,22447,22448,22449,22450,22451,22452,22453,
8224622454,22455,22456,22457,22458,22459,22460,22461,22462,22463,22464,22465,
8224722466,22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,22477,
8224822478,22479,22480,22481,22482,22483,22484,22485,22486,22487,22488,22489,
8224922490,22491,22492,22493,22494,22495,22496,22497,22498,22499,22500,22501,
8225022502,22503,22504,22505,22506,22507,22508,22509,22510,22511,22512,22513,
8225122514,22515,22516,22517,22518,22519,22520,22521,22522,22523,22524,22525,
8225222526,22527,22528,22529,22530,22531,22532,22533,22534,22535,22536,22537,
8225322538,22539,22540,22541,22542,22543,22544,22545,22546,22547,22548,22549,
8225422550,22551,22552,22553,22554,22555,22556,22557,22558,22559,22560,22561,
8225522562,22563,22564,22565,22566,22567,22568,22569,22570,22571,22572,22573,
8225622574,22575,22576,22577,22578,22579,22580,22581,22582,22583,22584,22585,
8225722586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22596,22597,
8225822598,22599,22600,22601,22602,22603,22604,22605,22606,22607,22608,22609,
8225922610,22611,22612,22613,22614,22615,22616,22617,22618,22619,22620,22621,
8226022622,22623,22624,22625,22626,22627,22628,22629,22630,22631,22632,22633,
8226122634,22635,22636,22637,22638,22639,22640,22641,22642,22643,22644,22645,
8226222646,22647,22648,22649,22650,22651,22652,22653,22654,22655,22656,22657,
8226322658,22659,22660,22661,22662,22663,22664,22665,22666,22667,22668,22669,
8226422670,22671,22672,22673,22674,22675,22676,22677,22678,22679,22680,22681,
8226522682,22683,22684,22685,22686,22687,22688,22689,22690,22691,22692,22693,
8226622694,22695,22696,22697,22698,22699,22700,22701,22702,22703,22704,22705,
8226722706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22716,22717,
8226822718,22719,22720,22721,22722,22723,22724,22725,22726,22727,22728,22729,
8226922730,22731,22732,22733,22734,22735,22736,22737,22738,22739,22740,22741,
8227022742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,
8227122754,22755,22756,22757,22758,22759,22760,22761,22762,22763,22764,22765,
8227222766,22767,22768,22769,22770,22771,22772,22773,22774,22775,22776,22777,
8227322778,22779,22780,22781,22782,22783,22784,22785,22786,22787,22788,22789,
8227422790,22791,22792,22793,22794,22795,22796,22797,22798,22799,22800,22801,
8227522802,22803,22804,22805,22806,22807,22808,22809,22810,22811,22812,22813,
8227622814,22815,22816,22817,22818,22819,22820,22821,22822,22823,22824,22825,
8227722826,22827,22828,22829,22830,22831,22832,22833,22834,22835,22836,22837,
8227822838,22839,22840,22841,22842,22843,22844,22845,22846,22847,22848,22849,
8227922850,22851,22852,22853,22854,22855,22856,22857,22858,22859,22860,22861,
8228022862,22863,22864,22865,22866,22867,22868,22869,22870,22871,22872,22873,
8228122874,22875,22876,22877,22878,22879,22880,22881,22882,22883,22884,22885,
8228222886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,
8228322898,22899,22900,22901,22902,22903,22904,22905,22906,22907,22908,22909,
8228422910,22911,22912,22913,22914,22915,22916,22917,22918,22919,22920,22921,
8228522922,22923,22924,22925,22926,22927,22928,22929,22930,22931,22932,22933,
8228622934,22935,22936,22937,22938,22939,22940,22941,22942,22943,22944,22945,
8228722946,22947,22948,22949,22950,22951,22952,22953,22954,22955,22956,22957,
8228822958,22959,22960,22961,22962,22963,22964,22965,22966,22967,22968,22969,
8228922970,22971,22972,22973,22974,22975,22976,22977,22978,22979,22980,22981,
8229022982,22983,22984,22985,22986,22987,22988,22989,22990,22991,22992,22993,
8229122994,22995,22996,22997,22998,22999,23000,23001,23002,23003,23004,23005,
8229223006,23007,23008,23009,23010,23011,23012,23013,23014,23015,23016,23017,
8229323018,23019,23020,23021,23022,23023,23024,23025,23026,23027,23028,23029,
8229423030,23031,23032,23033,23034,23035,23036,23037,23038,23039,23040,23041,
8229523042,23043,23044,23045,23046,23047,23048,23049,23050,23051,23052,23053,
8229623054,23055,23056,23057,23058,23059,23060,23061,23062,23063,23064,23065,
8229723066,23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,23077,
8229823078,23079,23080,23081,23082,23083,23084,23085,23086,23087,23088,23089,
8229923090,23091,23092,23093,23094,23095,23096,23097,23098,23099,23100,23101,
8230023102,23103,23104,23105,23106,23107,23108,23109,23110,23111,23112,23113,
8230123114,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23125,
8230223126,23127,23128,23129,23130,23131,23132,23133,23134,23135,23136,23137,
8230323138,23139,23140,23141,23142,23143,23144,23145,23146,23147,23148,23149,
8230423150,23151,23152,23153,23154,23155,23156,23157,23158,23159,23160,23161,
8230523162,23163,23164,23165,23166,23167,23168,23169,23170,23171,23172,23173,
8230623174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,
8230723186,23187,23188,23189,23190,23191,23192,23193,23194,23195,23196,23197,
8230823198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,
8230923210,23211,23212,23213,23214,23215,23216,23217,23218,23219,23220,23221,
8231023222,23223,23224,23225,23226,23227,23228,23229,23230,23231,23232,23233,
8231123234,23235,23236,23237,23238,23239,23240,23241,23242,23243,23244,23245,
8231223246,23247,23248,23249,23250,23251,23252,23253,23254,23255,23256,23257,
8231323258,23259,23260,23261,23262,23263,23264,23265,23266,23267,23268,23269,
8231423270,23271,23272,23273,23274,23275,23276,23277,23278,23279,23280,23281,
8231523282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,
8231623294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23305,
8231723306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,
8231823318,23319,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,
8231923330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,
8232023342,23343,23344,23345,23346,23347,23348,23349,23350,23351,23352,23353,
8232123354,23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,23365,
8232223366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23376,23377,
8232323378,23379,23380,23381,23382,23383,23384,23385,23386,23387,23388,23389,
8232423390,23391,23392,23393,23394,23395,23396,23397,23398,23399,23400,23401,
8232523402,23403,23404,23405,23406,23407,23408,23409,23410,23411,23412,23413,
8232623414,23415,23416,23417,23418,23419,23420,23421,23422,23423,23424,23425,
8232723426,23427,23428,23429,23430,23431,23432,23433,23434,23435,23436,23437,
8232823438,23439,23440,23441,23442,23443,23444,23445,23446,23447,23448,23449,
8232923450,23451,23452,23453,23454,23455,23456,23457,23458,23459,23460,23461,
8233023462,23463,23464,23465,23466,23467,23468,23469,23470,23471,23472,23473,
8233123474,23475,23476,23477,23478,23479,23480,23481,23482,23483,23484,23485,
8233223486,23487,23488,23489,23490,23491,23492,23493,23494,23495,23496,23497,
8233323498,23499,23500,23501,23502,23503,23504,23505,23506,23507,23508,23509,
8233423510,23511,23512,23513,23514,23515,23516,23517,23518,23519,23520,23521,
8233523522,23523,23524,23525,23526,23527,23528,23529,23530,23531,23532,23533,
8233623534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23545,
8233723546,23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,23557,
8233823558,23559,23560,23561,23562,23563,23564,23565,23566,23567,23568,23569,
8233923570,23571,23572,23573,23574,23575,23576,23577,23578,23579,23580,23581,
8234023582,23583,23584,23585,23586,23587,23588,23589,23590,23591,23592,23593,
8234123594,23595,23596,23597,23598,23599,23600,23601,23602,23603,23604,23605,
8234223606,23607,23608,23609,23610,23611,23612,23613,23614,23615,23616,23617,
8234323618,23619,23620,23621,23622,23623,23624,23625,23626,23627,23628,23629,
8234423630,23631,23632,23633,23634,23635,23636,23637,23638,23639,23640,23641,
8234523642,23643,23644,23645,23646,23647,23648,23649,23650,23651,23652,23653,
8234623654,23655,23656,23657,23658,23659,23660,23661,23662,23663,23664,23665,
8234723666,23667,23668,23669,23670,23671,23672,23673,23674,23675,23676,23677,
8234823678,23679,23680,23681,23682,23683,23684,23685,23686,23687,23688,23689,
8234923690,23691,23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,
8235023702,23703,23704,23705,23706,23707,23708,23709,23710,23711,23712,23713,
8235123714,23715,23716,23717,23718,23719,23720,23721,23722,23723,23724,23725,
8235223726,23727,23728,23729,23730,23731,23732,23733,23734,23735,23736,23737,
8235323738,23739,23740,23741,23742,23743,23744,23745,23746,23747,23748,23749,
8235423750,23751,23752,23753,23754,23755,23756,23757,23758,23759,23760,23761,
8235523762,23763,23764,23765,23766,23767,23768,23769,23770,23771,23772,23773,
8235623774,23775,23776,23777,23778,23779,23780,23781,23782,23783,23784,23785,
8235723786,23787,23788,23789,23790,23791,23792,23793,23794,23795,23796,23797,
8235823798,23799,23800,23801,23802,23803,23804,23805,23806,23807,23808,23809,
8235923810,23811,23812,23813,23814,23815,23816,23817,23818,23819,23820,23821,
8236023822,23823,23824,23825,23826,23827,23828,23829,23830,23831,23832,23833,
8236123834,23835,23836,23837,23838,23839,23840,23841,23842,23843,23844,23845,
8236223846,23847,23848,23849,23850,23851,23852,23853,23854,23855,23856,23857,
8236323858,23859,23860,23861,23862,23863,23864,23865,23866,23867,23868,23869,
8236423870,23871,23872,23873,23874,23875,23876,23877,23878,23879,23880,23881,
8236523882,23883,23884,23885,23886,23887,23888,23889,23890,23891,23892,23893,
8236623894,23895,23896,23897,23898,23899,23900,23901,23902,23903,23904,23905,
8236723906,23907,23908,23909,23910,23911,23912,23913,23914,23915,23916,23917,
8236823918,23919,23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,
8236923930,23931,23932,23933,23934,23935,23936,23937,23938,23939,23940,23941,
8237023942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,
8237123954,23955,23956,23957,23958,23959,23960,23961,23962,23963,23964,23965,
8237223966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,
8237323978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,
8237423990,23991,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,
8237524002,24003,24004,24005,24006,24007,24008,24009,24010,24011,24012,24013,
8237624014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,
8237724026,24027,24028,24029,24030,24031,24032,24033,24034,24035,24036,24037,
8237824038,24039,24040,24041,24042,24043,24044,24045,24046,24047,24048,24049,
8237924050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,
8238024062,24063,24064,24065,24066,24067,24068,24069,24070,24071,24072,24073,
8238124074,24075,24076,24077,24078,24079,24080,24081,24082,24083,24084,24085,
8238224086,24087,24088,24089,24090,24091,24092,24093,24094,24095,24096,24097,
8238324098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109,
8238424110,24111,24112,24113,24114,24115,24116,24117,24118,24119,24120,24121,
8238524122,24123,24124,24125,24126,24127,24128,24129,24130,24131,24132,24133,
8238624134,24135,24136,24137,24138,24139,24140,24141,24142,24143,24144,24145,
8238724146,24147,24148,24149,24150,24151,24152,24153,24154,24155,24156,24157,
8238824158,24159,24160,24161,24162,24163,24164,24165,24166,24167,24168,24169,
8238924170,24171,24172,24173,24174,24175,24176,24177,24178,24179,24180,24181,
8239024182,24183,24184,24185,24186,24187,24188,24189,24190,24191,24192,24193,
8239124194,24195,24196,24197,24198,24199,24200,24201,24202,24203,24204,24205,
8239224206,24207,24208,24209,24210,24211,24212,24213,24214,24215,24216,24217,
8239324218,24219,24220,24221,24222,24223,24224,24225,24226,24227,24228,24229,
8239424230,24231,24232,24233,24234,24235,24236,24237,24238,24239,24240,24241,
8239524242,24243,24244,24245,24246,24247,24248,24249,24250,24251,24252,24253,
8239624254,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24265,
8239724266,24267,24268,24269,24270,24271,24272,24273,24274,24275,24276,24277,
8239824278,24279,24280,24281,24282,24283,24284,24285,24286,24287,24288,24289,
8239924290,24291,24292,24293,24294,24295,24296,24297,24298,24299,24300,24301,
8240024302,24303,24304,24305,24306,24307,24308,24309,24310,24311,24312,24313,
8240124314,24315,24316,24317,24318,24319,24320,24321,24322,24323,24324,24325,
8240224326,24327,24328,24329,24330,24331,24332,24333,24334,24335,24336,24337,
8240324338,24339,24340,24341,24342,24343,24344,24345,24346,24347,24348,24349,
8240424350,24351,24352,24353,24354,24355,24356,24357,24358,24359,24360,24361,
8240524362,24363,24364,24365,24366,24367,24368,24369,24370,24371,24372,24373,
8240624374,24375,24376,24377,24378,24379,24380,24381,24382,24383,24384,24385,
8240724386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,
8240824398,24399,24400,24401,24402,24403,24404,24405,24406,24407,24408,24409,
8240924410,24411,24412,24413,24414,24415,24416,24417,24418,24419,24420,24421,
8241024422,24423,24424,24425,24426,24427,24428,24429,24430,24431,24432,24433,
8241124434,24435,24436,24437,24438,24439,24440,24441,24442,24443,24444,24445,
8241224446,24447,24448,24449,24450,24451,24452,24453,24454,24455,24456,24457,
8241324458,24459,24460,24461,24462,24463,24464,24465,24466,24467,24468,24469,
8241424470,24471,24472,24473,24474,24475,24476,24477,24478,24479,24480,24481,
8241524482,24483,24484,24485,24486,24487,24488,24489,24490,24491,24492,24493,
8241624494,24495,24496,24497,24498,24499,24500,24501,24502,24503,24504,24505,
8241724506,24507,24508,24509,24510,24511,24512,24513,24514,24515,24516,24517,
8241824518,24519,24520,24521,24522,24523,24524,24525,24526,24527,24528,24529,
8241924530,24531,24532,24533,24534,24535,24536,24537,24538,24539,24540,24541,
8242024542,24543,24544,24545,24546,24547,24548,24549,24550,24551,24552,24553,
8242124554,24555,24556,24557,24558,24559,24560,24561,24562,24563,24564,24565,
8242224566,24567,24568,24569,24570,24571,24572,24573,24574,24575,24576,24577,
8242324578,24579,24580,24581,24582,24583,24584,24585,24586,24587,24588,24589,
8242424590,24591,24592,24593,24594,24595,24596,24597,24598,24599,24600,24601,
8242524602,24603,24604,24605,24606,24607,24608,24609,24610,24611,24612,24613,
8242624614,24615,24616,24617,24618,24619,24620,24621,24622,24623,24624,24625,
8242724626,24627,24628,24629,24630,24631,24632,24633,24634,24635,24636,24637,
8242824638,24639,24640,24641,24642,24643,24644,24645,24646,24647,24648,24649,
8242924650,24651,24652,24653,24654,24655,24656,24657,24658,24659,24660,24661,
8243024662,24663,24664,24665,24666,24667,24668,24669,24670,24671,24672,24673,
8243124674,24675,24676,24677,24678,24679,24680,24681,24682,24683,24684,24685,
8243224686,24687,24688,24689,24690,24691,24692,24693,24694,24695,24696,24697,
8243324698,24699,24700,24701,24702,24703,24704,24705,24706,24707,24708,24709,
8243424710,24711,24712,24713,24714,24715,24716,24717,24718,24719,24720,24721,
8243524722,24723,24724,24725,24726,24727,24728,24729,24730,24731,24732,24733,
8243624734,24735,24736,24737,24738,24739,24740,24741,24742,24743,24744,24745,
8243724746,24747,24748,24749,24750,24751,24752,24753,24754,24755,24756,24757,
8243824758,24759,24760,24761,24762,24763,24764,24765,24766,24767,24768,24769,
8243924770,24771,24772,24773,24774,24775,24776,24777,24778,24779,24780,24781,
8244024782,24783,24784,24785,24786,24787,24788,24789,24790,24791,24792,24793,
8244124794,24795,24796,24797,24798,24799,24800,24801,24802,24803,24804,24805,
8244224806,24807,24808,24809,24810,24811,24812,24813,24814,24815,24816,24817,
8244324818,24819,24820,24821,24822,24823,24824,24825,24826,24827,24828,24829,
8244424830,24831,24832,24833,24834,24835,24836,24837,24838,24839,24840,24841,
8244524842,24843,24844,24845,24846,24847,24848,24849,24850,24851,24852,24853,
8244624854,24855,24856,24857,24858,24859,24860,24861,24862,24863,24864,24865,
8244724866,24867,24868,24869,24870,24871,24872,24873,24874,24875,24876,24877,
8244824878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,
8244924890,24891,24892,24893,24894,24895,24896,24897,24898,24899,24900,24901,
8245024902,24903,24904,24905,24906,24907,24908,24909,24910,24911,24912,24913,
8245124914,24915,24916,24917,24918,24919,24920,24921,24922,24923,24924,24925,
8245224926,24927,24928,24929,24930,24931,24932,24933,24934,24935,24936,24937,
8245324938,24939,24940,24941,24942,24943,24944,24945,24946,24947,24948,24949,
8245424950,24951,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,
8245524962,24963,24964,24965,24966,24967,24968,24969,24970,24971,24972,24973,
8245624974,24975,24976,24977,24978,24979,24980,24981,24982,24983,24984,24985,
8245724986,24987,24988,24989,24990,24991,24992,24993,24994,24995,24996,24997,
8245824998,24999,25000,25001,25002,25003,25004,25005,25006,25007,25008,25009,
8245925010,25011,25012,25013,25014,25015,25016,25017,25018,25019,25020,25021,
8246025022,25023,25024,25025,25026,25027,25028,25029,25030,25031,25032,25033,
8246125034,25035,25036,25037,25038,25039,25040,25041,25042,25043,25044,25045,
8246225046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,
8246325058,25059,25060,25061,25062,25063,25064,25065,25066,25067,25068,25069,
8246425070,25071,25072,25073,25074,25075,25076,25077,25078,25079,25080,25081,
8246525082,25083,25084,25085,25086,25087,25088,25089,25090,25091,25092,25093,
8246625094,25095,25096,25097,25098,25099,25100,25101,25102,25103,25104,25105,
8246725106,25107,25108,25109,25110,25111,25112,25113,25114,25115,25116,25117,
8246825118,25119,25120,25121,25122,25123,25124,25125,25126,25127,25128,25129,
8246925130,25131,25132,25133,25134,25135,25136,25137,25138,25139,25140,25141,
8247025142,25143,25144,25145,25146,25147,25148,25149,25150,25151,25152,25153,
8247125154,25155,25156,25157,25158,25159,25160,25161,25162,25163,25164,25165,
8247225166,25167,25168,25169,25170,25171,25172,25173,25174,25175,25176,25177,
8247325178,25179,25180,25181,25182,25183,25184,25185,25186,25187,25188,25189,
8247425190,25191,25192,25193,25194,25195,25196,25197,25198,25199,25200,25201,
8247525202,25203,25204,25205,25206,25207,25208,25209,25210,25211,25212,25213,
8247625214,25215,25216,25217,25218,25219,25220,25221,25222,25223,25224,25225,
8247725226,25227,25228,25229,25230,25231,25232,25233,25234,25235,25236,25237,
8247825238,25239,25240,25241,25242,25243,25244,25245,25246,25247,25248,25249,
8247925250,25251,25252,25253,25254,25255,25256,25257,25258,25259,25260,25261,
8248025262,25263,25264,25265,25266,25267,25268,25269,25270,25271,25272,25273,
8248125274,25275,25276,25277,25278,25279,25280,25281,25282,25283,25284,25285,
8248225286,25287,25288,25289,25290,25291,25292,25293,25294,25295,25296,25297,
8248325298,25299,25300,25301,25302,25303,25304,25305,25306,25307,25308,25309,
8248425310,25311,25312,25313,25314,25315,25316,25317,25318,25319,25320,25321,
8248525322,25323,25324,25325,25326,25327,25328,25329,25330,25331,25332,25333,
8248625334,25335,25336,25337,25338,25339,25340,25341,25342,25343,25344,25345,
8248725346,25347,25348,25349,25350,25351,25352,25353,25354,25355,25356,25357,
8248825358,25359,25360,25361,25362,25363,25364,25365,25366,25367,25368,25369,
8248925370,25371,25372,25373,25374,25375,25376,25377,25378,25379,25380,25381,
8249025382,25383,25384,25385,25386,25387,25388,25389,25390,25391,25392,25393,
8249125394,25395,25396,25397,25398,25399,25400,25401,25402,25403,25404,25405,
8249225406,25407,25408,25409,25410,25411,25412,25413,25414,25415,25416,25417,
8249325418,25419,25420,25421,25422,25423,25424,25425,25426,25427,25428,25429,
8249425430,25431,25432,25433,25434,25435,25436,25437,25438,25439,25440,25441,
8249525442,25443,25444,25445,25446,25447,25448,25449,25450,25451,25452,25453,
8249625454,25455,25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,
8249725466,25467,25468,25469,25470,25471,25472,25473,25474,25475,25476,25477,
8249825478,25479,25480,25481,25482,25483,25484,25485,25486,25487,25488,25489,
8249925490,25491,25492,25493,25494,25495,25496,25497,25498,25499,25500,25501,
8250025502,25503,25504,25505,25506,25507,25508,25509,25510,25511,25512,25513,
8250125514,25515,25516,25517,25518,25519,25520,25521,25522,25523,25524,25525,
8250225526,25527,25528,25529,25530,25531,25532,25533,25534,25535,25536,25537,
8250325538,25539,25540,25541,25542,25543,25544,25545,25546,25547,25548,25549,
8250425550,25551,25552,25553,25554,25555,25556,25557,25558,25559,25560,25561,
8250525562,25563,25564,25565,25566,25567,25568,25569,25570,25571,25572,25573,
8250625574,25575,25576,25577,25578,25579,25580,25581,25582,25583,25584,25585,
8250725586,25587,25588,25589,25590,25591,25592,25593,25594,25595,25596,25597,
8250825598,25599,25600,25601,25602,25603,25604,25605,25606,25607,25608,25609,
8250925610,25611,25612,25613,25614,25615,25616,25617,25618,25619,25620,25621,
8251025622,25623,25624,25625,25626,25627,25628,25629,25630,25631,25632,25633,
8251125634,25635,25636,25637,25638,25639,25640,25641,25642,25643,25644,25645,
8251225646,25647,25648,25649,25650,25651,25652,25653,25654,25655,25656,25657,
8251325658,25659,25660,25661,25662,25663,25664,25665,25666,25667,25668,25669,
8251425670,25671,25672,25673,25674,25675,25676,25677,25678,25679,25680,25681,
8251525682,25683,25684,25685,25686,25687,25688,25689,25690,25691,25692,25693,
8251625694,25695,25696,25697,25698,25699,25700,25701,25702,25703,25704,25705,
8251725706,25707,25708,25709,25710,25711,25712,25713,25714,25715,25716,25717,
8251825718,25719,25720,25721,25722,25723,25724,25725,25726,25727,25728,25729,
8251925730,25731,25732,25733,25734,25735,25736,25737,25738,25739,25740,25741,
8252025742,25743,25744,25745,25746,25747,25748,25749,25750,25751,25752,25753,
8252125754,25755,25756,25757,25758,25759,25760,25761,25762,25763,25764,25765,
8252225766,25767,25768,25769,25770,25771,25772,25773,25774,25775,25776,25777,
8252325778,25779,25780,25781,25782,25783,25784,25785,25786,25787,25788,25789,
8252425790,25791,25792,25793,25794,25795,25796,25797,25798,25799,25800,25801,
8252525802,25803,25804,25805,25806,25807,25808,25809,25810,25811,25812,25813,
8252625814,25815,25816,25817,25818,25819,25820,25821,25822,25823,25824,25825,
8252725826,25827,25828,25829,25830,25831,25832,25833,25834,25835,25836,25837,
8252825838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,
8252925850,25851,25852,25853,25854,25855,25856,25857,25858,25859,25860,25861,
8253025862,25863,25864,25865,25866,25867,25868,25869,25870,25871,25872,25873,
8253125874,25875,25876,25877,25878,25879,25880,25881,25882,25883,25884,25885,
8253225886,25887,25888,25889,25890,25891,25892,25893,25894,25895,25896,25897,
8253325898,25899,25900,25901,25902,25903,25904,25905,25906,25907,25908,25909,
8253425910,25911,25912,25913,25914,25915,25916,25917,25918,25919,25920,25921,
8253525922,25923,25924,25925,25926,25927,25928,25929,25930,25931,25932,25933,
8253625934,25935,25936,25937,25938,25939,25940,25941,25942,25943,25944,25945,
8253725946,25947,25948,25949,25950,25951,25952,25953,25954,25955,25956,25957,
8253825958,25959,25960,25961,25962,25963,25964,25965,25966,25967,25968,25969,
8253925970,25971,25972,25973,25974,25975,25976,25977,25978,25979,25980,25981,
8254025982,25983,25984,25985,25986,25987,25988,25989,25990,25991,25992,25993,
8254125994,25995,25996,25997,25998,25999,26000,26001,26002,26003,26004,26005,
8254226006,26007,26008,26009,26010,26011,26012,26013,26014,26015,26016,26017,
8254326018,26019,26020,26021,26022,26023,26024,26025,26026,26027,26028,26029,
8254426030,26031,26032,26033,26034,26035,26036,26037,26038,26039,26040,26041,
8254526042,26043,26044,26045,26046,26047,26048,26049,26050,26051,26052,26053,
8254626054,26055,26056,26057,26058,26059,26060,26061,26062,26063,26064,26065,
8254726066,26067,26068,26069,26070,26071,26072,26073,26074,26075,26076,26077,
8254826078,26079,26080,26081,26082,26083,26084,26085,26086,26087,26088,26089,
8254926090,26091,26092,26093,26094,26095,26096,26097,26098,26099,26100,26101,
8255026102,26103,26104,26105,26106,26107,26108,26109,26110,26111,26112,26113,
8255126114,26115,26116,26117,26118,26119,26120,26121,26122,26123,26124,26125,
8255226126,26127,26128,26129,26130,26131,26132,26133,26134,26135,26136,26137,
8255326138,26139,26140,26141,26142,26143,26144,26145,26146,26147,26148,26149,
8255426150,26151,26152,26153,26154,26155,26156,26157,26158,26159,26160,26161,
8255526162,26163,26164,26165,26166,26167,26168,26169,26170,26171,26172,26173,
8255626174,26175,26176,26177,26178,26179,26180,26181,26182,26183,26184,26185,
8255726186,26187,26188,26189,26190,26191,26192,26193,26194,26195,26196,26197,
8255826198,26199,26200,26201,26202,26203,26204,26205,26206,26207,26208,26209,
8255926210,26211,26212,26213,26214,26215,26216,26217,26218,26219,26220,26221,
8256026222,26223,26224,26225,26226,26227,26228,26229,26230,26231,26232,26233,
8256126234,26235,26236,26237,26238,26239,26240,26241,26242,26243,26244,26245,
8256226246,26247,26248,26249,26250,26251,26252,26253,26254,26255,26256,26257,
8256326258,26259,26260,26261,26262,26263,26264,26265,26266,26267,26268,26269,
8256426270,26271,26272,26273,26274,26275,26276,26277,26278,26279,26280,26281,
8256526282,26283,26284,26285,26286,26287,26288,26289,26290,26291,26292,26293,
8256626294,26295,26296,26297,26298,26299,26300,26301,26302,26303,26304,26305,
8256726306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,
8256826318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26329,
8256926330,26331,26332,26333,26334,26335,26336,26337,26338,26339,26340,26341,
8257026342,26343,26344,26345,26346,26347,26348,26349,26350,26351,26352,26353,
8257126354,26355,26356,26357,26358,26359,26360,26361,26362,26363,26364,26365,
8257226366,26367,26368,26369,26370,26371,26372,26373,26374,26375,26376,26377,
8257326378,26379,26380,26381,26382,26383,26384,26385,26386,26387,26388,26389,
8257426390,26391,26392,26393,26394,26395,26396,26397,26398,26399,26400,26401,
8257526402,26403,26404,26405,26406,26407,26408,26409,26410,26411,26412,26413,
8257626414,26415,26416,26417,26418,26419,26420,26421,26422,26423,26424,26425,
8257726426,26427,26428,26429,26430,26431,26432,26433,26434,26435,26436,26437,
8257826438,26439,26440,26441,26442,26443,26444,26445,26446,26447,26448,26449,
8257926450,26451,26452,26453,26454,26455,26456,26457,26458,26459,26460,26461,
8258026462,26463,26464,26465,26466,26467,26468,26469,26470,26471,26472,26473,
8258126474,26475,26476,26477,26478,26479,26480,26481,26482,26483,26484,26485,
8258226486,26487,26488,26489,26490,26491,26492,26493,26494,26495,26496,26497,
8258326498,26499,26500,26501,26502,26503,26504,26505,26506,26507,26508,26509,
8258426510,26511,26512,26513,26514,26515,26516,26517,26518,26519,26520,26521,
8258526522,26523,26524,26525,26526,26527,26528,26529,26530,26531,26532,26533,
8258626534,26535,26536,26537,26538,26539,26540,26541,26542,26543,26544,26545,
8258726546,26547,26548,26549,26550,26551,26552,26553,26554,26555,26556,26557,
8258826558,26559,26560,26561,26562,26563,26564,26565,26566,26567,26568,26569,
8258926570,26571,26572,26573,26574,26575,26576,26577,26578,26579,26580,26581,
8259026582,26583,26584,26585,26586,26587,26588,26589,26590,26591,26592,26593,
8259126594,26595,26596,26597,26598,26599,26600,26601,26602,26603,26604,26605,
8259226606,26607,26608,26609,26610,26611,26612,26613,26614,26615,26616,26617,
8259326618,26619,26620,26621,26622,26623,26624,26625,26626,26627,26628,26629,
8259426630,26631,26632,26633,26634,26635,26636,26637,26638,26639,26640,26641,
8259526642,26643,26644,26645,26646,26647,26648,26649,26650,26651,26652,26653,
8259626654,26655,26656,26657,26658,26659,26660,26661,26662,26663,26664,26665,
8259726666,26667,26668,26669,26670,26671,26672,26673,26674,26675,26676,26677,
8259826678,26679,26680,26681,26682,26683,26684,26685,26686,26687,26688,26689,
8259926690,26691,26692,26693,26694,26695,26696,26697,26698,26699,26700,26701,
8260026702,26703,26704,26705,26706,26707,26708,26709,26710,26711,26712,26713,
8260126714,26715,26716,26717,26718,26719,26720,26721,26722,26723,26724,26725,
8260226726,26727,26728,26729,26730,26731,26732,26733,26734,26735,26736,26737,
8260326738,26739,26740,26741,26742,26743,26744,26745,26746,26747,26748,26749,
8260426750,26751,26752,26753,26754,26755,26756,26757,26758,26759,26760,26761,
8260526762,26763,26764,26765,26766,26767,26768,26769,26770,26771,26772,26773,
8260626774,26775,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,
8260726786,26787,26788,26789,26790,26791,26792,26793,26794,26795,26796,26797,
8260826798,26799,26800,26801,26802,26803,26804,26805,26806,26807,26808,26809,
8260926810,26811,26812,26813,26814,26815,26816,26817,26818,26819,26820,26821,
8261026822,26823,26824,26825,26826,26827,26828,26829,26830,26831,26832,26833,
8261126834,26835,26836,26837,26838,26839,26840,26841,26842,26843,26844,26845,
8261226846,26847,26848,26849,26850,26851,26852,26853,26854,26855,26856,26857,
8261326858,26859,26860,26861,26862,26863,26864,26865,26866,26867,26868,26869,
8261426870,26871,26872,26873,26874,26875,26876,26877,26878,26879,26880,26881,
8261526882,26883,26884,26885,26886,26887,26888,26889,26890,26891,26892,26893,
8261626894,26895,26896,26897,26898,26899,26900,26901,26902,26903,26904,26905,
8261726906,26907,26908,26909,26910,26911,26912,26913,26914,26915,26916,26917,
8261826918,26919,26920,26921,26922,26923,26924,26925,26926,26927,26928,26929,
8261926930,26931,26932,26933,26934,26935,26936,26937,26938,26939,26940,26941,
8262026942,26943,26944,26945,26946,26947,26948,26949,26950,26951,26952,26953,
8262126954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26964,26965,
8262226966,26967,26968,26969,26970,26971,26972,26973,26974,26975,26976,26977,
8262326978,26979,26980,26981,26982,26983,26984,26985,26986,26987,26988,26989,
8262426990,26991,26992,26993,26994,26995,26996,26997,26998,26999,27000,27001,
8262527002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,
8262627014,27015,27016,27017,27018,27019,27020,27021,27022,27023,27024,27025,
8262727026,27027,27028,27029,27030,27031,27032,27033,27034,27035,27036,27037,
8262827038,27039,27040,27041,27042,27043,27044,27045,27046,27047,27048,27049,
8262927050,27051,27052,27053,27054,27055,27056,27057,27058,27059,27060,27061,
8263027062,27063,27064,27065,27066,27067,27068,27069,27070,27071,27072,27073,
8263127074,27075,27076,27077,27078,27079,27080,27081,27082,27083,27084,27085,
8263227086,27087,27088,27089,27090,27091,27092,27093,27094,27095,27096,27097,
8263327098,27099,27100,27101,27102,27103,27104,27105,27106,27107,27108,27109,
8263427110,27111,27112,27113,27114,27115,27116,27117,27118,27119,27120,27121,
8263527122,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27133,
8263627134,27135,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,
8263727146,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,
8263827158,27159,27160,27161,27162,27163,27164,27165,27166,27167,27168,27169,
8263927170,27171,27172,27173,27174,27175,27176,27177,27178,27179,27180,27181,
8264027182,27183,27184,27185,27186,27187,27188,27189,27190,27191,27192,27193,
8264127194,27195,27196,27197,27198,27199,27200,27201,27202,27203,27204,27205,
8264227206,27207,27208,27209,27210,27211,27212,27213,27214,27215,27216,27217,
8264327218,27219,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229,
8264427230,27231,27232,27233,27234,27235,27236,27237,27238,27239,27240,27241,
8264527242,27243,27244,27245,27246,27247,27248,27249,27250,27251,27252,27253,
8264627254,27255,27256,27257,27258,27259,27260,27261,27262,27263,27264,27265,
8264727266,27267,27268,27269,27270,27271,27272,27273,27274,27275,27276,27277,
8264827278,27279,27280,27281,27282,27283,27284,27285,27286,27287,27288,27289,
8264927290,27291,27292,27293,27294,27295,27296,27297,27298,27299,27300,27301,
8265027302,27303,27304,27305,27306,27307,27308,27309,27310,27311,27312,27313,
8265127314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,
8265227326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,
8265327338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,
8265427350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,
8265527362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,
8265627374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,
8265727386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,
8265827398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,
8265927410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,
8266027422,27423,27424,27425,27426,27427,27428,27429,27430,27431,27432,27433,
8266127434,27435,27436,27437,27438,27439,27440,27441,27442,27443,27444,27445,
8266227446,27447,27448,27449,27450,27451,27452,27453,27454,27455,27456,27457,
8266327458,27459,27460,27461,27462,27463,27464,27465,27466,27467,27468,27469,
8266427470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27481,
8266527482,27483,27484,27485,27486,27487,27488,27489,27490,27491,27492,27493,
8266627494,27495,27496,27497,27498,27499,27500,27501,27502,27503,27504,27505,
8266727506,27507,27508,27509,27510,27511,27512,27513,27514,27515,27516,27517,
8266827518,27519,27520,27521,27522,27523,27524,27525,27526,27527,27528,27529,
8266927530,27531,27532,27533,27534,27535,27536,27537,27538,27539,27540,27541,
8267027542,27543,27544,27545,27546,27547,27548,27549,27550,27551,27552,27553,
8267127554,27555,27556,27557,27558,27559,27560,27561,27562,27563,27564,27565,
8267227566,27567,27568,27569,27570,27571,27572,27573,27574,27575,27576,27577,
8267327578,27579,27580,27581,27582,27583,27584,27585,27586,27587,27588,27589,
8267427590,27591,27592,27593,27594,27595,27596,27597,27598,27599,27600,27601,
8267527602,27603,27604,27605,27606,27607,27608,27609,27610,27611,27612,27613,
8267627614,27615,27616,27617,27618,27619,27620,27621,27622,27623,27624,27625,
8267727626,27627,27628,27629,27630,27631,27632,27633,27634,27635,27636,27637,
8267827638,27639,27640,27641,27642,27643,27644,27645,27646,27647,27648,27649,
8267927650,27651,27652,27653,27654,27655,27656,27657,27658,27659,27660,27661,
8268027662,27663,27664,27665,27666,27667,27668,27669,27670,27671,27672,27673,
8268127674,27675,27676,27677,27678,27679,27680,27681,27682,27683,27684,27685,
8268227686,27687,27688,27689,27690,27691,27692,27693,27694,27695,27696,27697,
8268327698,27699,27700,27701,27702,27703,27704,27705,27706,27707,27708,27709,
8268427710,27711,27712,27713,27714,27715,27716,27717,27718,27719,27720,27721,
8268527722,27723,27724,27725,27726,27727,27728,27729,27730,27731,27732,27733,
8268627734,27735,27736,27737,27738,27739,27740,27741,27742,27743,27744,27745,
8268727746,27747,27748,27749,27750,27751,27752,27753,27754,27755,27756,27757,
8268827758,27759,27760,27761,27762,27763,27764,27765,27766,27767,27768,27769,
8268927770,27771,27772,27773,27774,27775,27776,27777,27778,27779,27780,27781,
8269027782,27783,27784,27785,27786,27787,27788,27789,27790,27791,27792,27793,
8269127794,27795,27796,27797,27798,27799,27800,27801,27802,27803,27804,27805,
8269227806,27807,27808,27809,27810,27811,27812,27813,27814,27815,27816,27817,
8269327818,27819,27820,27821,27822,27823,27824,27825,27826,27827,27828,27829,
8269427830,27831,27832,27833,27834,27835,27836,27837,27838,27839,27840,27841,
8269527842,27843,27844,27845,27846,27847,27848,27849,27850,27851,27852,27853,
8269627854,27855,27856,27857,27858,27859,27860,27861,27862,27863,27864,27865,
8269727866,27867,27868,27869,27870,27871,27872,27873,27874,27875,27876,27877,
8269827878,27879,27880,27881,27882,27883,27884,27885,27886,27887,27888,27889,
8269927890,27891,27892,27893,27894,27895,27896,27897,27898,27899,27900,27901,
8270027902,27903,27904,27905,27906,27907,27908,27909,27910,27911,27912,27913,
8270127914,27915,27916,27917,27918,27919,27920,27921,27922,27923,27924,27925,
8270227926,27927,27928,27929,27930,27931,27932,27933,27934,27935,27936,27937,
8270327938,27939,27940,27941,27942,27943,27944,27945,27946,27947,27948,27949,
8270427950,27951,27952,27953,27954,27955,27956,27957,27958,27959,27960,27961,
8270527962,27963,27964,27965,27966,27967,27968,27969,27970,27971,27972,27973,
8270627974,27975,27976,27977,27978,27979,27980,27981,27982,27983,27984,27985,
8270727986,27987,27988,27989,27990,27991,27992,27993,27994,27995,27996,27997,
8270827998,27999,28000,28001,28002,28003,28004,28005,28006,28007,28008,28009,
8270928010,28011,28012,28013,28014,28015,28016,28017,28018,28019,28020,28021,
8271028022,28023,28024,28025,28026,28027,28028,28029,28030,28031,28032,28033,
8271128034,28035,28036,28037,28038,28039,28040,28041,28042,28043,28044,28045,
8271228046,28047,28048,28049,28050,28051,28052,28053,28054,28055,28056,28057,
8271328058,28059,28060,28061,28062,28063,28064,28065,28066,28067,28068,28069,
8271428070,28071,28072,28073,28074,28075,28076,28077,28078,28079,28080,28081,
8271528082,28083,28084,28085,28086,28087,28088,28089,28090,28091,28092,28093,
8271628094,28095,28096,28097,28098,28099,28100,28101,28102,28103,28104,28105,
8271728106,28107,28108,28109,28110,28111,28112,28113,28114,28115,28116,28117,
8271828118,28119,28120,28121,28122,28123,28124,28125,28126,28127,28128,28129,
8271928130,28131,28132,28133,28134,28135,28136,28137,28138,28139,28140,28141,
8272028142,28143,28144,28145,28146,28147,28148,28149,28150,28151,28152,28153,
8272128154,28155,28156,28157,28158,28159,28160,28161,28162,28163,28164,28165,
8272228166,28167,28168,28169,28170,28171,28172,28173,28174,28175,28176,28177,
8272328178,28179,28180,28181,28182,28183,28184,28185,28186,28187,28188,28189,
8272428190,28191,28192,28193,28194,28195,28196,28197,28198,28199,28200,28201,
8272528202,28203,28204,28205,28206,28207,28208,28209,28210,28211,28212,28213,
8272628214,28215,28216,28217,28218,28219,28220,28221,28222,28223,28224,28225,
8272728226,28227,28228,28229,28230,28231,28232,28233,28234,28235,28236,28237,
8272828238,28239,28240,28241,28242,28243,28244,28245,28246,28247,28248,28249,
8272928250,28251,28252,28253,28254,28255,28256,28257,28258,28259,28260,28261,
8273028262,28263,28264,28265,28266,28267,28268,28269,28270,28271,28272,28273,
8273128274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,
8273228286,28287,28288,28289,28290,28291,28292,28293,28294,28295,28296,28297,
8273328298,28299,28300,28301,28302,28303,28304,28305,28306,28307,28308,28309,
8273428310,28311,28312,28313,28314,28315,28316,28317,28318,28319,28320,28321,
8273528322,28323,28324,28325,28326,28327,28328,28329,28330,28331,28332,28333,
8273628334,28335,28336,28337,28338,28339,28340,28341,28342,28343,28344,28345,
8273728346,28347,28348,28349,28350,28351,28352,28353,28354,28355,28356,28357,
8273828358,28359,28360,28361,28362,28363,28364,28365,28366,28367,28368,28369,
8273928370,28371,28372,28373,28374,28375,28376,28377,28378,28379,28380,28381,
8274028382,28383,28384,28385,28386,28387,28388,28389,28390,28391,28392,28393,
8274128394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28404,28405,
8274228406,28407,28408,28409,28410,28411,28412,28413,28414,28415,28416,28417,
8274328418,28419,28420,28421,28422,28423,28424,28425,28426,28427,28428,28429,
8274428430,28431,28432,28433,28434,28435,28436,28437,28438,28439,28440,28441,
8274528442,28443,28444,28445,28446,28447,28448,28449,28450,28451,28452,28453,
8274628454,28455,28456,28457,28458,28459,28460,28461,28462,28463,28464,28465,
8274728466,28467,28468,28469,28470,28471,28472,28473,28474,28475,28476,28477,
8274828478,28479,28480,28481,28482,28483,28484,28485,28486,28487,28488,28489,
8274928490,28491,28492,28493,28494,28495,28496,28497,28498,28499,28500,28501,
8275028502,28503,28504,28505,28506,28507,28508,28509,28510,28511,28512,28513,
8275128514,28515,28516,28517,28518,28519,28520,28521,28522,28523,28524,28525,
8275228526,28527,28528,28529,28530,28531,28532,28533,28534,28535,28536,28537,
8275328538,28539,28540,28541,28542,28543,28544,28545,28546,28547,28548,28549,
8275428550,28551,28552,28553,28554,28555,28556,28557,28558,28559,28560,28561,
8275528562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28572,28573,
8275628574,28575,28576,28577,28578,28579,28580,28581,28582,28583,28584,28585,
8275728586,28587,28588,28589,28590,28591,28592,28593,28594,28595,28596,28597,
8275828598,28599,28600,28601,28602,28603,28604,28605,28606,28607,28608,28609,
8275928610,28611,28612,28613,28614,28615,28616,28617,28618,28619,28620,28621,
8276028622,28623,28624,28625,28626,28627,28628,28629,28630,28631,28632,28633,
8276128634,28635,28636,28637,28638,28639,28640,28641,28642,28643,28644,28645,
8276228646,28647,28648,28649,28650,28651,28652,28653,28654,28655,28656,28657,
8276328658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,
8276428670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,
8276528682,28683,28684,28685,28686,28687,28688,28689,28690,28691,28692,28693,
8276628694,28695,28696,28697,28698,28699,28700,28701,28702,28703,28704,28705,
8276728706,28707,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,
8276828718,28719,28720,28721,28722,28723,28724,28725,28726,28727,28728,28729,
8276928730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,
8277028742,28743,28744,28745,28746,28747,28748,28749,28750,28751,28752,28753,
8277128754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,
8277228766,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,
8277328778,28779,28780,28781,28782,28783,28784,28785,28786,28787,28788,28789,
8277428790,28791,28792,28793,28794,28795,28796,28797,28798,28799,28800,28801,
8277528802,28803,28804,28805,28806,28807,28808,28809,28810,28811,28812,28813,
8277628814,28815,28816,28817,28818,28819,28820,28821,28822,28823,28824,28825,
8277728826,28827,28828,28829,28830,28831,28832,28833,28834,28835,28836,28837,
8277828838,28839,28840,28841,28842,28843,28844,28845,28846,28847,28848,28849,
8277928850,28851,28852,28853,28854,28855,28856,28857,28858,28859,28860,28861,
8278028862,28863,28864,28865,28866,28867,28868,28869,28870,28871,28872,28873,
8278128874,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,
8278228886,28887,28888,28889,28890,28891,28892,28893,28894,28895,28896,28897,
8278328898,28899,28900,28901,28902,28903,28904,28905,28906,28907,28908,28909,
8278428910,28911,28912,28913,28914,28915,28916,28917,28918,28919,28920,28921,
8278528922,28923,28924,28925,28926,28927,28928,28929,28930,28931,28932,28933,
8278628934,28935,28936,28937,28938,28939,28940,28941,28942,28943,28944,28945,
8278728946,28947,28948,28949,28950,28951,28952,28953,28954,28955,28956,28957,
8278828958,28959,28960,28961,28962,28963,28964,28965,28966,28967,28968,28969,
8278928970,28971,28972,28973,28974,28975,28976,28977,28978,28979,28980,28981,
8279028982,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,
8279128994,28995,28996,28997,28998,28999,29000,29001,29002,29003,29004,29005,
8279229006,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,
8279329018,29019,29020,29021,29022,29023,29024,29025,29026,29027,29028,29029,
8279429030,29031,29032,29033,29034,29035,29036,29037,29038,29039,29040,29041,
8279529042,29043,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,
8279629054,29055,29056,29057,29058,29059,29060,29061,29062,29063,29064,29065,
8279729066,29067,29068,29069,29070,29071,29072,29073,29074,29075,29076,29077,
8279829078,29079,29080,29081,29082,29083,29084,29085,29086,29087,29088,29089,
8279929090,29091,29092,29093,29094,29095,29096,29097,29098,29099,29100,29101,
8280029102,29103,29104,29105,29106,29107,29108,29109,29110,29111,29112,29113,
8280129114,29115,29116,29117,29118,29119,29120,29121,29122,29123,29124,29125,
8280229126,29127,29128,29129,29130,29131,29132,29133,29134,29135,29136,29137,
8280329138,29139,29140,29141,29142,29143,29144,29145,29146,29147,29148,29149,
8280429150,29151,29152,29153,29154,29155,29156,29157,29158,29159,29160,29161,
8280529162,29163,29164,29165,29166,29167,29168,29169,29170,29171,29172,29173,
8280629174,29175,29176,29177,29178,29179,29180,29181,29182,29183,29184,29185,
8280729186,29187,29188,29189,29190,29191,29192,29193,29194,29195,29196,29197,
8280829198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,
8280929210,29211,29212,29213,29214,29215,29216,29217,29218,29219,29220,29221,
8281029222,29223,29224,29225,29226,29227,29228,29229,29230,29231,29232,29233,
8281129234,29235,29236,29237,29238,29239,29240,29241,29242,29243,29244,29245,
8281229246,29247,29248,29249,29250,29251,29252,29253,29254,29255,29256,29257,
8281329258,29259,29260,29261,29262,29263,29264,29265,29266,29267,29268,29269,
8281429270,29271,29272,29273,29274,29275,29276,29277,29278,29279,29280,29281,
8281529282,29283,29284,29285,29286,29287,29288,29289,29290,29291,29292,29293,
8281629294,29295,29296,29297,29298,29299,29300,29301,29302,29303,29304,29305,
8281729306,29307,29308,29309,29310,29311,29312,29313,29314,29315,29316,29317,
8281829318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,
8281929330,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,
8282029342,29343,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,
8282129354,29355,29356,29357,29358,29359,29360,29361,29362,29363,29364,29365,
8282229366,29367,29368,29369,29370,29371,29372,29373,29374,29375,29376,29377,
8282329378,29379,29380,29381,29382,29383,29384,29385,29386,29387,29388,29389,
8282429390,29391,29392,29393,29394,29395,29396,29397,29398,29399,29400,29401,
8282529402,29403,29404,29405,29406,29407,29408,29409,29410,29411,29412,29413,
8282629414,29415,29416,29417,29418,29419,29420,29421,29422,29423,29424,29425,
8282729426,29427,29428,29429,29430,29431,29432,29433,29434,29435,29436,29437,
8282829438,29439,29440,29441,29442,29443,29444,29445,29446,29447,29448,29449,
8282929450,29451,29452,29453,29454,29455,29456,29457,29458,29459,29460,29461,
8283029462,29463,29464,29465,29466,29467,29468,29469,29470,29471,29472,29473,
8283129474,29475,29476,29477,29478,29479,29480,29481,29482,29483,29484,29485,
8283229486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,
8283329498,29499,29500,29501,29502,29503,29504,29505,29506,29507,29508,29509,
8283429510,29511,29512,29513,29514,29515,29516,29517,29518,29519,29520,29521,
8283529522,29523,29524,29525,29526,29527,29528,29529,29530,29531,29532,29533,
8283629534,29535,29536,29537,29538,29539,29540,29541,29542,29543,29544,29545,
8283729546,29547,29548,29549,29550,29551,29552,29553,29554,29555,29556,29557,
8283829558,29559,29560,29561,29562,29563,29564,29565,29566,29567,29568,29569,
8283929570,29571,29572,29573,29574,29575,29576,29577,29578,29579,29580,29581,
8284029582,29583,29584,29585,29586,29587,29588,29589,29590,29591,29592,29593,
8284129594,29595,29596,29597,29598,29599,29600,29601,29602,29603,29604,29605,
8284229606,29607,29608,29609,29610,29611,29612,29613,29614,29615,29616,29617,
8284329618,29619,29620,29621,29622,29623,29624,29625,29626,29627,29628,29629,
8284429630,29631,29632,29633,29634,29635,29636,29637,29638,29639,29640,29641,
8284529642,29643,29644,29645,29646,29647,29648,29649,29650,29651,29652,29653,
8284629654,29655,29656,29657,29658,29659,29660,29661,29662,29663,29664,29665,
8284729666,29667,29668,29669,29670,29671,29672,29673,29674,29675,29676,29677,
8284829678,29679,29680,29681,29682,29683,29684,29685,29686,29687,29688,29689,
8284929690,29691,29692,29693,29694,29695,29696,29697,29698,29699,29700,29701,
8285029702,29703,29704,29705,29706,29707,29708,29709,29710,29711,29712,29713,
8285129714,29715,29716,29717,29718,29719,29720,29721,29722,29723,29724,29725,
8285229726,29727,29728,29729,29730,29731,29732,29733,29734,29735,29736,29737,
8285329738,29739,29740,29741,29742,29743,29744,29745,29746,29747,29748,29749,
8285429750,29751,29752,29753,29754,29755,29756,29757,29758,29759,29760,29761,
8285529762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,
8285629774,29775,29776,29777,29778,29779,29780,29781,29782,29783,29784,29785,
8285729786,29787,29788,29789,29790,29791,29792,29793,29794,29795,29796,29797,
8285829798,29799,29800,29801,29802,29803,29804,29805,29806,29807,29808,29809,
8285929810,29811,29812,29813,29814,29815,29816,29817,29818,29819,29820,29821,
8286029822,29823,29824,29825,29826,29827,29828,29829,29830,29831,29832,29833,
8286129834,29835,29836,29837,29838,29839,29840,29841,29842,29843,29844,29845,
8286229846,29847,29848,29849,29850,29851,29852,29853,29854,29855,29856,29857,
8286329858,29859,29860,29861,29862,29863,29864,29865,29866,29867,29868,29869,
8286429870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,
8286529882,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,
8286629894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,
8286729906,29907,29908,29909,29910,29911,29912,29913,29914,29915,29916,29917,
8286829918,29919,29920,29921,29922,29923,29924,29925,29926,29927,29928,29929,
8286929930,29931,29932,29933,29934,29935,29936,29937,29938,29939,29940,29941,
8287029942,29943,29944,29945,29946,29947,29948,29949,29950,29951,29952,29953,
8287129954,29955,29956,29957,29958,29959,29960,29961,29962,29963,29964,29965,
8287229966,29967,29968,29969,29970,29971,29972,29973,29974,29975,29976,29977,
8287329978,29979,29980,29981,29982,29983,29984,29985,29986,29987,29988,29989,
8287429990,29991,29992,29993,29994,29995,29996,29997,29998,29999,30000,30001,
8287530002,30003,30004,30005,30006,30007,30008,30009,30010,30011,30012,30013,
8287630014,30015,30016,30017,30018,30019,30020,30021,30022,30023,30024,30025,
8287730026,30027,30028,30029,30030,30031,30032,30033,30034,30035,30036,30037,
8287830038,30039,30040,30041,30042,30043,30044,30045,30046,30047,30048,30049,
8287930050,30051,30052,30053,30054,30055,30056,30057,30058,30059,30060,30061,
8288030062,30063,30064,30065,30066,30067,30068,30069,30070,30071,30072,30073,
8288130074,30075,30076,30077,30078,30079,30080,30081,30082,30083,30084,30085,
8288230086,30087,30088,30089,30090,30091,30092,30093,30094,30095,30096,30097,
8288330098,30099,30100,30101,30102,30103,30104,30105,30106,30107,30108,30109,
8288430110,30111,30112,30113,30114,30115,30116,30117,30118,30119,30120,30121,
8288530122,30123,30124,30125,30126,30127,30128,30129,30130,30131,30132,30133,
8288630134,30135,30136,30137,30138,30139,30140,30141,30142,30143,30144,30145,
8288730146,30147,30148,30149,30150,30151,30152,30153,30154,30155,30156,30157,
8288830158,30159,30160,30161,30162,30163,30164,30165,30166,30167,30168,30169,
8288930170,30171,30172,30173,30174,30175,30176,30177,30178,30179,30180,30181,
8289030182,30183,30184,30185,30186,30187,30188,30189,30190,30191,30192,30193,
8289130194,30195,30196,30197,30198,30199,30200,30201,30202,30203,30204,30205,
8289230206,30207,30208,30209,30210,30211,30212,30213,30214,30215,30216,30217,
8289330218,30219,30220,30221,30222,30223,30224,30225,30226,30227,30228,30229,
8289430230,30231,30232,30233,30234,30235,30236,30237,30238,30239,30240,30241,
8289530242,30243,30244,30245,30246,30247,30248,30249,30250,30251,30252,30253,
8289630254,30255,30256,30257,30258,30259,30260,30261,30262,30263,30264,30265,
8289730266,30267,30268,30269,30270,30271,30272,30273,30274,30275,30276,30277,
8289830278,30279,30280,30281,30282,30283,30284,30285,30286,30287,30288,30289,
8289930290,30291,30292,30293,30294,30295,30296,30297,30298,30299,30300,30301,
8290030302,30303,30304,30305,30306,30307,30308,30309,30310,30311,30312,30313,
8290130314,30315,30316,30317,30318,30319,30320,30321,30322,30323,30324,30325,
8290230326,30327,30328,30329,30330,30331,30332,30333,30334,30335,30336,30337,
8290330338,30339,30340,30341,30342,30343,30344,30345,30346,30347,30348,30349,
8290430350,30351,30352,30353,30354,30355,30356,30357,30358,30359,30360,30361,
8290530362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30372,30373,
8290630374,30375,30376,30377,30378,30379,30380,30381,30382,30383,30384,30385,
8290730386,30387,30388,30389,30390,30391,30392,30393,30394,30395,30396,30397,
8290830398,30399,30400,30401,30402,30403,30404,30405,30406,30407,30408,30409,
8290930410,30411,30412,30413,30414,30415,30416,30417,30418,30419,30420,30421,
8291030422,30423,30424,30425,30426,30427,30428,30429,30430,30431,30432,30433,
8291130434,30435,30436,30437,30438,30439,30440,30441,30442,30443,30444,30445,
8291230446,30447,30448,30449,30450,30451,30452,30453,30454,30455,30456,30457,
8291330458,30459,30460,30461,30462,30463,30464,30465,30466,30467,30468,30469,
8291430470,30471,30472,30473,30474,30475,30476,30477,30478,30479,30480,30481,
8291530482,30483,30484,30485,30486,30487,30488,30489,30490,30491,30492,30493,
8291630494,30495,30496,30497,30498,30499,30500,30501,30502,30503,30504,30505,
8291730506,30507,30508,30509,30510,30511,30512,30513,30514,30515,30516,30517,
8291830518,30519,30520,30521,30522,30523,30524,30525,30526,30527,30528,30529,
8291930530,30531,30532,30533,30534,30535,30536,30537,30538,30539,30540,30541,
8292030542,30543,30544,30545,30546,30547,30548,30549,30550,30551,30552,30553,
8292130554,30555,30556,30557,30558,30559,30560,30561,30562,30563,30564,30565,
8292230566,30567,30568,30569,30570,30571,30572,30573,30574,30575,30576,30577,
8292330578,30579,30580,30581,30582,30583,30584,30585,30586,30587,30588,30589,
8292430590,30591,30592,30593,30594,30595,30596,30597,30598,30599,30600,30601,
8292530602,30603,30604,30605,30606,30607,30608,30609,30610,30611,30612,30613,
8292630614,30615,30616,30617,30618,30619,30620,30621,30622,30623,30624,30625,
8292730626,30627,30628,30629,30630,30631,30632,30633,30634,30635,30636,30637,
8292830638,30639,30640,30641,30642,30643,30644,30645,30646,30647,30648,30649,
8292930650,30651,30652,30653,30654,30655,30656,30657,30658,30659,30660,30661,
8293030662,30663,30664,30665,30666,30667,30668,30669,30670,30671,30672,30673,
8293130674,30675,30676,30677,30678,30679,30680,30681,30682,30683,30684,30685,
8293230686,30687,30688,30689,30690,30691,30692,30693,30694,30695,30696,30697,
8293330698,30699,30700,30701,30702,30703,30704,30705,30706,30707,30708,30709,
8293430710,30711,30712,30713,30714,30715,30716,30717,30718,30719,30720,30721,
8293530722,30723,30724,30725,30726,30727,30728,30729,30730,30731,30732,30733,
8293630734,30735,30736,30737,30738,30739,30740,30741,30742,30743,30744,30745,
8293730746,30747,30748,30749,30750,30751,30752,30753,30754,30755,30756,30757,
8293830758,30759,30760,30761,30762,30763,30764,30765,30766,30767,30768,30769,
8293930770,30771,30772,30773,30774,30775,30776,30777,30778,30779,30780,30781,
8294030782,30783,30784,30785,30786,30787,30788,30789,30790,30791,30792,30793,
8294130794,30795,30796,30797,30798,30799,30800,30801,30802,30803,30804,30805,
8294230806,30807,30808,30809,30810,30811,30812,30813,30814,30815,30816,30817,
8294330818,30819,30820,30821,30822,30823,30824,30825,30826,30827,30828,30829,
8294430830,30831,30832,30833,30834,30835,30836,30837,30838,30839,30840,30841,
8294530842,30843,30844,30845,30846,30847,30848,30849,30850,30851,30852,30853,
8294630854,30855,30856,30857,30858,30859,30860,30861,30862,30863,30864,30865,
8294730866,30867,30868,30869,30870,30871,30872,30873,30874,30875,30876,30877,
8294830878,30879,30880,30881,30882,30883,30884,30885,30886,30887,30888,30889,
8294930890,30891,30892,30893,30894,30895,30896,30897,30898,30899,30900,30901,
8295030902,30903,30904,30905,30906,30907,30908,30909,30910,30911,30912,30913,
8295130914,30915,30916,30917,30918,30919,30920,30921,30922,30923,30924,30925,
8295230926,30927,30928,30929,30930,30931,30932,30933,30934,30935,30936,30937,
8295330938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,
8295430950,30951,30952,30953,30954,30955,30956,30957,30958,30959,30960,30961,
8295530962,30963,30964,30965,30966,30967,30968,30969,30970,30971,30972,30973,
8295630974,30975,30976,30977,30978,30979,30980,30981,30982,30983,30984,30985,
8295730986,30987,30988,30989,30990,30991,30992,30993,30994,30995,30996,30997,
8295830998,30999,31000,31001,31002,31003,31004,31005,31006,31007,31008,31009,
8295931010,31011,31012,31013,31014,31015,31016,31017,31018,31019,31020,31021,
8296031022,31023,31024,31025,31026,31027,31028,31029,31030,31031,31032,31033,
8296131034,31035,31036,31037,31038,31039,31040,31041,31042,31043,31044,31045,
8296231046,31047,31048,31049,31050,31051,31052,31053,31054,31055,31056,31057,
8296331058,31059,31060,31061,31062,31063,31064,31065,31066,31067,31068,31069,
8296431070,31071,31072,31073,31074,31075,31076,31077,31078,31079,31080,31081,
8296531082,31083,31084,31085,31086,31087,31088,31089,31090,31091,31092,31093,
8296631094,31095,31096,31097,31098,31099,31100,31101,31102,31103,31104,31105,
8296731106,31107,31108,31109,31110,31111,31112,31113,31114,31115,31116,31117,
8296831118,31119,31120,31121,31122,31123,31124,31125,31126,31127,31128,31129,
8296931130,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,
8297031142,31143,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,
8297131154,31155,31156,31157,31158,31159,31160,31161,31162,31163,31164,31165,
8297231166,31167,31168,31169,31170,31171,31172,31173,31174,31175,31176,31177,
8297331178,31179,31180,31181,31182,31183,31184,31185,31186,31187,31188,31189,
8297431190,31191,31192,31193,31194,31195,31196,31197,31198,31199,31200,31201,
8297531202,31203,31204,31205,31206,31207,31208,31209,31210,31211,31212,31213,
8297631214,31215,31216,31217,31218,31219,31220,31221,31222,31223,31224,31225,
8297731226,31227,31228,31229,31230,31231,31232,31233,31234,31235,31236,31237,
8297831238,31239,31240,31241,31242,31243,31244,31245,31246,31247,31248,31249,
8297931250,31251,31252,31253,31254,31255,31256,31257,31258,31259,31260,31261,
8298031262,31263,31264,31265,31266,31267,31268,31269,31270,31271,31272,31273,
8298131274,31275,31276,31277,31278,31279,31280,31281,31282,31283,31284,31285,
8298231286,31287,31288,31289,31290,31291,31292,31293,31294,31295,31296,31297,
8298331298,31299,31300,31301,31302,31303,31304,31305,31306,31307,31308,31309,
8298431310,31311,31312,31313,31314,31315,31316,31317,31318,31319,31320,31321,
8298531322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,
8298631334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31344,31345,
8298731346,31347,31348,31349,31350,31351,31352,31353,31354,31355,31356,31357,
8298831358,31359,31360,31361,31362,31363,31364,31365,31366,31367,31368,31369,
8298931370,31371,31372,31373,31374,31375,31376,31377,31378,31379,31380,31381,
8299031382,31383,31384,31385,31386,31387,31388,31389,31390,31391,31392,31393,
8299131394,31395,31396,31397,31398,31399,31400,31401,31402,31403,31404,31405,
8299231406,31407,31408,31409,31410,31411,31412,31413,31414,31415,31416,31417,
8299331418,31419,31420,31421,31422,31423,31424,31425,31426,31427,31428,31429,
8299431430,31431,31432,31433,31434,31435,31436,31437,31438,31439,31440,31441,
8299531442,31443,31444,31445,31446,31447,31448,31449,31450,31451,31452,31453,
8299631454,31455,31456,31457,31458,31459,31460,31461,31462,31463,31464,31465,
8299731466,31467,31468,31469,31470,31471,31472,31473,31474,31475,31476,31477,
8299831478,31479,31480,31481,31482,31483,31484,31485,31486,31487,31488,31489,
8299931490,31491,31492,31493,31494,31495,31496,31497,31498,31499,31500,31501,
8300031502,31503,31504,31505,31506,31507,31508,31509,31510,31511,31512,31513,
8300131514,31515,31516,31517,31518,31519,31520,31521,31522,31523,31524,31525,
8300231526,31527,31528,31529,31530,31531,31532,31533,31534,31535,31536,31537,
8300331538,31539,31540,31541,31542,31543,31544,31545,31546,31547,31548,31549,
8300431550,31551,31552,31553,31554,31555,31556,31557,31558,31559,31560,31561,
8300531562,31563,31564,31565,31566,31567,31568,31569,31570,31571,31572,31573,
8300631574,31575,31576,31577,31578,31579,31580,31581,31582,31583,31584,31585,
8300731586,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,
8300831598,31599,31600,31601,31602,31603,31604,31605,31606,31607,31608,31609,
8300931610,31611,31612,31613,31614,31615,31616,31617,31618,31619,31620,31621,
8301031622,31623,31624,31625,31626,31627,31628,31629,31630,31631,31632,31633,
8301131634,31635,31636,31637,31638,31639,31640,31641,31642,31643,31644,31645,
8301231646,31647,31648,31649,31650,31651,31652,31653,31654,31655,31656,31657,
8301331658,31659,31660,31661,31662,31663,31664,31665,31666,31667,31668,31669,
8301431670,31671,31672,31673,31674,31675,31676,31677,31678,31679,31680,31681,
8301531682,31683,31684,31685,31686,31687,31688,31689,31690,31691,31692,31693,
8301631694,31695,31696,31697,31698,31699,31700,31701,31702,31703,31704,31705,
8301731706,31707,31708,31709,31710,31711,31712,31713,31714,31715,31716,31717,
8301831718,31719,31720,31721,31722,31723,31724,31725,31726,31727,31728,31729,
8301931730,31731,31732,31733,31734,31735,31736,31737,31738,31739,31740,31741,
8302031742,31743,31744,31745,31746,31747,31748,31749,31750,31751,31752,31753,
8302131754,31755,31756,31757,31758,31759,31760,31761,31762,31763,31764,31765,
8302231766,31767,31768,31769,31770,31771,31772,31773,31774,31775,31776,31777,
8302331778,31779,31780,31781,31782,31783,31784,31785,31786,31787,31788,31789,
8302431790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31800,31801,
8302531802,31803,31804,31805,31806,31807,31808,31809,31810,31811,31812,31813,
8302631814,31815,31816,31817,31818,31819,31820,31821,31822,31823,31824,31825,
8302731826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,
8302831838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,
8302931850,31851,31852,31853,31854,31855,31856,31857,31858,31859,31860,31861,
8303031862,31863,31864,31865,31866,31867,31868,31869,31870,31871,31872,31873,
8303131874,31875,31876,31877,31878,31879,31880,31881,31882,31883,31884,31885,
8303231886,31887,31888,31889,31890,31891,31892,31893,31894,31895,31896,31897,
8303331898,31899,31900,31901,31902,31903,31904,31905,31906,31907,31908,31909,
8303431910,31911,31912,31913,31914,31915,31916,31917,31918,31919,31920,31921,
8303531922,31923,31924,31925,31926,31927,31928,31929,31930,31931,31932,31933,
8303631934,31935,31936,31937,31938,31939,31940,31941,31942,31943,31944,31945,
8303731946,31947,31948,31949,31950,31951,31952,31953,31954,31955,31956,31957,
8303831958,31959,31960,31961,31962,31963,31964,31965,31966,31967,31968,31969,
8303931970,31971,31972,31973,31974,31975,31976,31977,31978,31979,31980,31981,
8304031982,31983,31984,31985,31986,31987,31988,31989,31990,31991,31992,31993,
8304131994,31995,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,
8304232006,32007,32008,32009,32010,32011,32012,32013,32014,32015,32016,32017,
8304332018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,
8304432030,32031,32032,32033,32034,32035,32036,32037,32038,32039,32040,32041,
8304532042,32043,32044,32045,32046,32047,32048,32049,32050,32051,32052,32053,
8304632054,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,
8304732066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,
8304832078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,
8304932090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,
8305032102,32103,32104,32105,32106,32107,32108,32109,32110,32111,32112,32113,
8305132114,32115,32116,32117,32118,32119,32120,32121,32122,32123,32124,32125,
8305232126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,
8305332138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,
8305432150,32151,32152,32153,32154,32155,32156,32157,32158,32159,32160,32161,
8305532162,32163,32164,32165,32166,32167,32168,32169,32170,32171,32172,32173,
8305632174,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,
8305732186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,
8305832198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,
8305932210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,
8306032222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,
8306132234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,
8306232246,32247,32248,32249,32250,32251,32252,32253,32254,32255,32256,32257,
8306332258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,
8306432270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,
8306532282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,
8306632294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,
8306732306,32307,32308,32309,32310,32311,32312,32313,32314,32315,32316,32317,
8306832318,32319,32320,32321,32322,32323,32324,32325,32326,32327,32328,32329,
8306932330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,
8307032342,32343,32344,32345,32346,32347,32348,32349,32350,32351,32352,32353,
8307132354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,
8307232366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,
8307332378,32379,32380,32381,32382,32383,32384,32385,32386,32387,32388,32389,
8307432390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,
8307532402,32403,32404,32405,32406,32407,32408,32409,32410,32411,32412,32413,
8307632414,32415,32416,32417,32418,32419,32420,32421,32422,32423,32424,32425,
8307732426,32427,32428,32429,32430,32431,32432,32433,32434,32435,32436,32437,
8307832438,32439,32440,32441,32442,32443,32444,32445,32446,32447,32448,32449,
8307932450,32451,32452,32453,32454,32455,32456,32457,32458,32459,32460,32461,
8308032462,32463,32464,32465,32466,32467,32468,32469,32470,32471,32472,32473,
8308132474,32475,32476,32477,32478,32479,32480,32481,32482,32483,32484,32485,
8308232486,32487,32488,32489,32490,32491,32492,32493,32494,32495,32496,32497,
8308332498,32499,32500,32501,32502,32503,32504,32505,32506,32507,32508,32509,
8308432510,32511,32512,32513,32514,32515,32516,32517,32518,32519,32520,32521,
8308532522,32523,32524,32525,32526,32527,32528,32529,32530,32531,32532,32533,
8308632534,32535,32536,32537,32538,32539,32540,32541,32542,32543,32544,32545,
8308732546,32547,32548,32549,32550,32551,32552,32553,32554,32555,32556,32557,
8308832558,32559,32560,32561,32562,32563,32564,32565,32566,32567,32568,32569,
8308932570,32571,32572,32573,32574,32575,32576,32577,32578,32579,32580,32581,
8309032582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32592,32593,
8309132594,32595,32596,32597,32598,32599,32600,32601,32602,32603,32604,32605,
8309232606,32607,32608,32609,32610,32611,32612,32613,32614,32615,32616,32617,
8309332618,32619,32620,32621,32622,32623,32624,32625,32626,32627,32628,32629,
8309432630,32631,32632,32633,32634,32635,32636,32637,32638,32639,32640,32641,
8309532642,32643,32644,32645,32646,32647,32648,32649,32650,32651,32652,32653,
8309632654,32655,32656,32657,32658,32659,32660,32661,32662,32663,32664,32665,
8309732666,32667,32668,32669,32670,32671,32672,32673,32674,32675,32676,32677,
8309832678,32679,32680,32681,32682,32683,32684,32685,32686,32687,32688,32689,
8309932690,32691,32692,32693,32694,32695,32696,32697,32698,32699,32700,32701,
8310032702,32703,32704,32705,32706,32707,32708,32709,32710,32711,32712,32713,
8310132714,32715,32716,32717,32718,32719,32720,32721,32722,32723,32724,32725,
8310232726,32727,32728,32729,32730,32731,32732,32733,32734,32735,32736,32737,
8310332738,32739,32740,32741,32742,32743,32744,32745,32746,32747,32748,32749,
8310432750,32751,32752,32753,32754,32755,32756,32757,32758,32759,32760,32761,
8310532762,32763,32764,32765,32766,32767,32768L,32769L,32770L,32771L,32772L,
8310632773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L,32781L,32782L,
8310732783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L,32791L,32792L,
8310832793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L,32801L,32802L,
8310932803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L,32811L,32812L,
8311032813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L,32821L,32822L,
8311132823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L,32831L,32832L,
8311232833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L,32841L,32842L,
8311332843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L,32851L,32852L,
8311432853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L,32861L,32862L,
8311532863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L,32871L,32872L,
8311632873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L,32881L,32882L,
8311732883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L,32891L,32892L,
8311832893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L,32901L,32902L,
8311932903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L,32911L,32912L,
8312032913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L,32921L,32922L,
8312132923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L,32931L,32932L,
8312232933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L,32941L,32942L,
8312332943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L,32951L,32952L,
8312432953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L,32961L,32962L,
8312532963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L,32971L,32972L,
8312632973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L,32981L,32982L,
8312732983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L,32991L,32992L,
8312832993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L,33001L,33002L,
8312933003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L,33011L,33012L,
8313033013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L,33021L,33022L,
8313133023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L,33031L,33032L,
8313233033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L,33041L,33042L,
8313333043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L,33051L,33052L,
8313433053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L,33061L,33062L,
8313533063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L,33071L,33072L,
8313633073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L,33081L,33082L,
8313733083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L,33091L,33092L,
8313833093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L,33101L,33102L,
8313933103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L,33111L,33112L,
8314033113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L,33121L,33122L,
8314133123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L,33131L,33132L,
8314233133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L,33141L,33142L,
8314333143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L,33151L,33152L,
8314433153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L,33161L,33162L,
8314533163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L,33171L,33172L,
8314633173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L,33181L,33182L,
8314733183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L,33191L,33192L,
8314833193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L,33201L,33202L,
8314933203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L,33211L,33212L,
8315033213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L,33221L,33222L,
8315133223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L,33231L,33232L,
8315233233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L,33241L,33242L,
8315333243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L,33251L,33252L,
8315433253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L,33261L,33262L,
8315533263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L,33271L,33272L,
8315633273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L,33281L,33282L,
8315733283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L,33291L,33292L,
8315833293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L,33301L,33302L,
8315933303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L,33311L,33312L,
8316033313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L,33321L,33322L,
8316133323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L,33331L,33332L,
8316233333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L,33341L,33342L,
8316333343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L,33351L,33352L,
8316433353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L,33361L,33362L,
8316533363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L,33371L,33372L,
8316633373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L,33381L,33382L,
8316733383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L,33391L,33392L,
8316833393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L,33401L,33402L,
8316933403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L,33411L,33412L,
8317033413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L,33421L,33422L,
8317133423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L,33431L,33432L,
8317233433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L,33441L,33442L,
8317333443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L,33451L,33452L,
8317433453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L,33461L,33462L,
8317533463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L,33471L,33472L,
8317633473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L,33481L,33482L,
8317733483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L,33491L,33492L,
8317833493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L,33501L,33502L,
8317933503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L,33511L,33512L,
8318033513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L,33521L,33522L,
8318133523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L,33531L,33532L,
8318233533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L,33541L,33542L,
8318333543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L,33551L,33552L,
8318433553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L,33561L,33562L,
8318533563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L,33571L,33572L,
8318633573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L,33581L,33582L,
8318733583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L,33591L,33592L,
8318833593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L,33601L,33602L,
8318933603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L,33611L,33612L,
8319033613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L,33621L,33622L,
8319133623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L,33631L,33632L,
8319233633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L,33641L,33642L,
8319333643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L,33651L,33652L,
8319433653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L,33661L,33662L,
8319533663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L,33671L,33672L,
8319633673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L,33681L,33682L,
8319733683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L,33691L,33692L,
8319833693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L,33701L,33702L,
8319933703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L,33711L,33712L,
8320033713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L,33721L,33722L,
8320133723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L,33731L,33732L,
8320233733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L,33741L,33742L,
8320333743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L,33751L,33752L,
8320433753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L,33761L,33762L,
8320533763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L,33771L,33772L,
8320633773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L,33781L,33782L,
8320733783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L,33791L,33792L,
8320833793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L,33801L,33802L,
8320933803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L,33811L,33812L,
8321033813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L,33821L,33822L,
8321133823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L,33831L,33832L,
8321233833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L,33841L,33842L,
8321333843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L,33851L,33852L,
8321433853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L,33861L,33862L,
8321533863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L,33871L,33872L,
8321633873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L,33881L,33882L,
8321733883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L,33891L,33892L,
8321833893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L,33901L,33902L,
8321933903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L,33911L,33912L,
8322033913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L,33921L,33922L,
8322133923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L,33931L,33932L,
8322233933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L,33941L,33942L,
8322333943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L,33951L,33952L,
8322433953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L,33961L,33962L,
8322533963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L,33971L,33972L,
8322633973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L,33981L,33982L,
8322733983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L,33991L,33992L,
8322833993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L,34001L,34002L,
8322934003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L,34011L,34012L,
8323034013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L,34021L,34022L,
8323134023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L,34031L,34032L,
8323234033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L,34041L,34042L,
8323334043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L,34051L,34052L,
8323434053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L,34061L,34062L,
8323534063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L,34071L,34072L,
8323634073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L,34081L,34082L,
8323734083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L,34091L,34092L,
8323834093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L,34101L,34102L,
8323934103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L,34111L,34112L,
8324034113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L,34121L,34122L,
8324134123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L,34131L,34132L,
8324234133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L,34141L,34142L,
8324334143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L,34151L,34152L,
8324434153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L,34161L,34162L,
8324534163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L,34171L,34172L,
8324634173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L,34181L,34182L,
8324734183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L,34191L,34192L,
8324834193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L,34201L,34202L,
8324934203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L,34211L,34212L,
8325034213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L,34221L,34222L,
8325134223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L,34231L,34232L,
8325234233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L,34241L,34242L,
8325334243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L,34251L,34252L,
8325434253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L,34261L,34262L,
8325534263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L,34271L,34272L,
8325634273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L,34281L,34282L,
8325734283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L,34291L,34292L,
8325834293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L,34301L,34302L,
8325934303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L,34311L,34312L,
8326034313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L,34321L,34322L,
8326134323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L,34331L,34332L,
8326234333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L,34341L,34342L,
8326334343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L,34351L,34352L,
8326434353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L,34361L,34362L,
8326534363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L,34371L,34372L,
8326634373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L,34381L,34382L,
8326734383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L,34391L,34392L,
8326834393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L,34401L,34402L,
8326934403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L,34411L,34412L,
8327034413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L,34421L,34422L,
8327134423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L,34431L,34432L,
8327234433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L,34441L,34442L,
8327334443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L,34451L,34452L,
8327434453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L,34461L,34462L,
8327534463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L,34471L,34472L,
8327634473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L,34481L,34482L,
8327734483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L,34491L,34492L,
8327834493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L,34501L,34502L,
8327934503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L,34511L,34512L,
8328034513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L,34521L,34522L,
8328134523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L,34531L,34532L,
8328234533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L,34541L,34542L,
8328334543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L,34551L,34552L,
8328434553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L,34561L,34562L,
8328534563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L,34571L,34572L,
8328634573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L,34581L,34582L,
8328734583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L,34591L,34592L,
8328834593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L,34601L,34602L,
8328934603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L,34611L,34612L,
8329034613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L,34621L,34622L,
8329134623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L,34631L,34632L,
8329234633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L,34641L,34642L,
8329334643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L,34651L,34652L,
8329434653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L,34661L,34662L,
8329534663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L,34671L,34672L,
8329634673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L,34681L,34682L,
8329734683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L,34691L,34692L,
8329834693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L,34701L,34702L,
8329934703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L,34711L,34712L,
8330034713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L,34721L,34722L,
8330134723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L,34731L,34732L,
8330234733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L,34741L,34742L,
8330334743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L,34751L,34752L,
8330434753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L,34761L,34762L,
8330534763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L,34771L,34772L,
8330634773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L,34781L,34782L,
8330734783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L,34791L,34792L,
8330834793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L,34801L,34802L,
8330934803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L,34811L,34812L,
8331034813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L,34821L,34822L,
8331134823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L,34831L,34832L,
8331234833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L,34841L,34842L,
8331334843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L,34851L,34852L,
8331434853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L,34861L,34862L,
8331534863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L,34871L,34872L,
8331634873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L,34881L,34882L,
8331734883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L,34891L,34892L,
8331834893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L,34901L,34902L,
8331934903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L,34911L,34912L,
8332034913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L,34921L,34922L,
8332134923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L,34931L,34932L,
8332234933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L,34941L,34942L,
8332334943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L,34951L,34952L,
8332434953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L,34961L,34962L,
8332534963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L,34971L,34972L,
8332634973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L,34981L,34982L,
8332734983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L,34991L,34992L,
8332834993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L,35001L,35002L,
8332935003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L,35011L,35012L,
8333035013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L,35021L,35022L,
8333135023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L,35031L,35032L,
8333235033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L,35041L,35042L,
8333335043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L,35051L,35052L,
8333435053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L,35061L,35062L,
8333535063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L,35071L,35072L,
8333635073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L,35081L,35082L,
8333735083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L,35091L,35092L,
8333835093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L,35101L,35102L,
8333935103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L,35111L,35112L,
8334035113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L,35121L,35122L,
8334135123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L,35131L,35132L,
8334235133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L,35141L,35142L,
8334335143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L,35151L,35152L,
8334435153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L,35161L,35162L,
8334535163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L,35171L,35172L,
8334635173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L,35181L,35182L,
8334735183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L,35191L,35192L,
8334835193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L,35201L,35202L,
8334935203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L,35211L,35212L,
8335035213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L,35221L,35222L,
8335135223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L,35231L,35232L,
8335235233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L,35241L,35242L,
8335335243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L,35251L,35252L,
8335435253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L,35261L,35262L,
8335535263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L,35271L,35272L,
8335635273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L,35281L,35282L,
8335735283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L,35291L,35292L,
8335835293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L,35301L,35302L,
8335935303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L,35311L,35312L,
8336035313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L,35321L,35322L,
8336135323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L,35331L,35332L,
8336235333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L,35341L,35342L,
8336335343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L,35351L,35352L,
8336435353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L,35361L,35362L,
8336535363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L,35371L,35372L,
8336635373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L,35381L,35382L,
8336735383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L,35391L,35392L,
8336835393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L,35401L,35402L,
8336935403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L,35411L,35412L,
8337035413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L,35421L,35422L,
8337135423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L,35431L,35432L,
8337235433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L,35441L,35442L,
8337335443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L,35451L,35452L,
8337435453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L,35461L,35462L,
8337535463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L,35471L,35472L,
8337635473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L,35481L,35482L,
8337735483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L,35491L,35492L,
8337835493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L,35501L,35502L,
8337935503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L,35511L,35512L,
8338035513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L,35521L,35522L,
8338135523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L,35531L,35532L,
8338235533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L,35541L,35542L,
8338335543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L,35551L,35552L,
8338435553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L,35561L,35562L,
8338535563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L,35571L,35572L,
8338635573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L,35581L,35582L,
8338735583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L,35591L,35592L,
8338835593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L,35601L,35602L,
8338935603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L,35611L,35612L,
8339035613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L,35621L,35622L,
8339135623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L,35631L,35632L,
8339235633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L,35641L,35642L,
8339335643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L,35651L,35652L,
8339435653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L,35661L,35662L,
8339535663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L,35671L,35672L,
8339635673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L,35681L,35682L,
8339735683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L,35691L,35692L,
8339835693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L,35701L,35702L,
8339935703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L,35711L,35712L,
8340035713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L,35721L,35722L,
8340135723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L,35731L,35732L,
8340235733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L,35741L,35742L,
8340335743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L,35751L,35752L,
8340435753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L,35761L,35762L,
8340535763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L,35771L,35772L,
8340635773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L,35781L,35782L,
8340735783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L,35791L,35792L,
8340835793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L,35801L,35802L,
8340935803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L,35811L,35812L,
8341035813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L,35821L,35822L,
8341135823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L,35831L,35832L,
8341235833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L,35841L,35842L,
8341335843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L,35851L,35852L,
8341435853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L,35861L,35862L,
8341535863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L,35871L,35872L,
8341635873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L,35881L,35882L,
8341735883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L,35891L,35892L,
8341835893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L,35901L,35902L,
8341935903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L,35911L,35912L,
8342035913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L,35921L,35922L,
8342135923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L,35931L,35932L,
8342235933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L,35941L,35942L,
8342335943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L,35951L,35952L,
8342435953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L,35961L,35962L,
8342535963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L,35971L,35972L,
8342635973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L,35981L,35982L,
8342735983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L,35991L,35992L,
8342835993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L,36001L,36002L,
8342936003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L,36011L,36012L,
8343036013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L,36021L,36022L,
8343136023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L,36031L,36032L,
8343236033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L,36041L,36042L,
8343336043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L,36051L,36052L,
8343436053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L,36061L,36062L,
8343536063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L,36071L,36072L,
8343636073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L,36081L,36082L,
8343736083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L,36091L,36092L,
8343836093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L,36101L,36102L,
8343936103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L,36111L,36112L,
8344036113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L,36121L,36122L,
8344136123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L,36131L,36132L,
8344236133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L,36141L,36142L,
8344336143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L,36151L,36152L,
8344436153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L,36161L,36162L,
8344536163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L,36171L,36172L,
8344636173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L,36181L,36182L,
8344736183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L,36191L,36192L,
8344836193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L,36201L,36202L,
8344936203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L,36211L,36212L,
8345036213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L,36221L,36222L,
8345136223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L,36231L,36232L,
8345236233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L,36241L,36242L,
8345336243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L,36251L,36252L,
8345436253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L,36261L,36262L,
8345536263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L,36271L,36272L,
8345636273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L,36281L,36282L,
8345736283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L,36291L,36292L,
8345836293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L,36301L,36302L,
8345936303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L,36311L,36312L,
8346036313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L,36321L,36322L,
8346136323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L,36331L,36332L,
8346236333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L,36341L,36342L,
8346336343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L,36351L,36352L,
8346436353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L,36361L,36362L,
8346536363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L,36371L,36372L,
8346636373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L,36381L,36382L,
8346736383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L,36391L,36392L,
8346836393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L,36401L,36402L,
8346936403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L,36411L,36412L,
8347036413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L,36421L,36422L,
8347136423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L,36431L,36432L,
8347236433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L,36441L,36442L,
8347336443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L,36451L,36452L,
8347436453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L,36461L,36462L,
8347536463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L,36471L,36472L,
8347636473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L,36481L,36482L,
8347736483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L,36491L,36492L,
8347836493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L,36501L,36502L,
8347936503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L,36511L,36512L,
8348036513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L,36521L,36522L,
8348136523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L,36531L,36532L,
8348236533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L,36541L,36542L,
8348336543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L,36551L,36552L,
8348436553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L,36561L,36562L,
8348536563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L,36571L,36572L,
8348636573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L,36581L,36582L,
8348736583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L,36591L,36592L,
8348836593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L,36601L,36602L,
8348936603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L,36611L,36612L,
8349036613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L,36621L,36622L,
8349136623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L,36631L,36632L,
8349236633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L,36641L,36642L,
8349336643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L,36651L,36652L,
8349436653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L,36661L,36662L,
8349536663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L,36671L,36672L,
8349636673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L,36681L,36682L,
8349736683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L,36691L,36692L,
8349836693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L,36701L,36702L,
8349936703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L,36711L,36712L,
8350036713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L,36721L,36722L,
8350136723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L,36731L,36732L,
8350236733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L,36741L,36742L,
8350336743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L,36751L,36752L,
8350436753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L,36761L,36762L,
8350536763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L,36771L,36772L,
8350636773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L,36781L,36782L,
8350736783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L,36791L,36792L,
8350836793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L,36801L,36802L,
8350936803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L,36811L,36812L,
8351036813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L,36821L,36822L,
8351136823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L,36831L,36832L,
8351236833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L,36841L,36842L,
8351336843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L,36851L,36852L,
8351436853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L,36861L,36862L,
8351536863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L,36871L,36872L,
8351636873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L,36881L,36882L,
8351736883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L,36891L,36892L,
8351836893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L,36901L,36902L,
8351936903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L,36911L,36912L,
8352036913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L,36921L,36922L,
8352136923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L,36931L,36932L,
8352236933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L,36941L,36942L,
8352336943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L,36951L,36952L,
8352436953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L,36961L,36962L,
8352536963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L,36971L,36972L,
8352636973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L,36981L,36982L,
8352736983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L,36991L,36992L,
8352836993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L,37001L,37002L,
8352937003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L,37011L,37012L,
8353037013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L,37021L,37022L,
8353137023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L,37031L,37032L,
8353237033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L,37041L,37042L,
8353337043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L,37051L,37052L,
8353437053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L,37061L,37062L,
8353537063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L,37071L,37072L,
8353637073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L,37081L,37082L,
8353737083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L,37091L,37092L,
8353837093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L,37101L,37102L,
8353937103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L,37111L,37112L,
8354037113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L,37121L,37122L,
8354137123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L,37131L,37132L,
8354237133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L,37141L,37142L,
8354337143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L,37151L,37152L,
8354437153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L,37161L,37162L,
8354537163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L,37171L,37172L,
8354637173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L,37181L,37182L,
8354737183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L,37191L,37192L,
8354837193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L,37201L,37202L,
8354937203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L,37211L,37212L,
8355037213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L,37221L,37222L,
8355137223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L,37231L,37232L,
8355237233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L,37241L,37242L,
8355337243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L,37251L,37252L,
8355437253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L,37261L,37262L,
8355537263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L,37271L,37272L,
8355637273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L,37281L,37282L,
8355737283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L,37291L,37292L,
8355837293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L,37301L,37302L,
8355937303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L,37311L,37312L,
8356037313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L,37321L,37322L,
8356137323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L,37331L,37332L,
8356237333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L,37341L,37342L,
8356337343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L,37351L,37352L,
8356437353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L,37361L,37362L,
8356537363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L,37371L,37372L,
8356637373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L,37381L,37382L,
8356737383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L,37391L,37392L,
8356837393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L,37401L,37402L,
8356937403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L,37411L,37412L,
8357037413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L,37421L,37422L,
8357137423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L,37431L,37432L,
8357237433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L,37441L,37442L,
8357337443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L,37451L,37452L,
8357437453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L,37461L,37462L,
8357537463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L,37471L,37472L,
8357637473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L,37481L,37482L,
8357737483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L,37491L,37492L,
8357837493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L,37501L,37502L,
8357937503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L,37511L,37512L,
8358037513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L,37521L,37522L,
8358137523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L,37531L,37532L,
8358237533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L,37541L,37542L,
8358337543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L,37551L,37552L,
8358437553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L,37561L,37562L,
8358537563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L,37571L,37572L,
8358637573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L,37581L,37582L,
8358737583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L,37591L,37592L,
8358837593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L,37601L,37602L,
8358937603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L,37611L,37612L,
8359037613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L,37621L,37622L,
8359137623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L,37631L,37632L,
8359237633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L,37641L,37642L,
8359337643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L,37651L,37652L,
8359437653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L,37661L,37662L,
8359537663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L,37671L,37672L,
8359637673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L,37681L,37682L,
8359737683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L,37691L,37692L,
8359837693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L,37701L,37702L,
8359937703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L,37711L,37712L,
8360037713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L,37721L,37722L,
8360137723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L,37731L,37732L,
8360237733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L,37741L,37742L,
8360337743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L,37751L,37752L,
8360437753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L,37761L,37762L,
8360537763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L,37771L,37772L,
8360637773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L,37781L,37782L,
8360737783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L,37791L,37792L,
8360837793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L,37801L,37802L,
8360937803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L,37811L,37812L,
8361037813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L,37821L,37822L,
8361137823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L,37831L,37832L,
8361237833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L,37841L,37842L,
8361337843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L,37851L,37852L,
8361437853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L,37861L,37862L,
8361537863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L,37871L,37872L,
8361637873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L,37881L,37882L,
8361737883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L,37891L,37892L,
8361837893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L,37901L,37902L,
8361937903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L,37911L,37912L,
8362037913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L,37921L,37922L,
8362137923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L,37931L,37932L,
8362237933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L,37941L,37942L,
8362337943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L,37951L,37952L,
8362437953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L,37961L,37962L,
8362537963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L,37971L,37972L,
8362637973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L,37981L,37982L,
8362737983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L,37991L,37992L,
8362837993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L,38001L,38002L,
8362938003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L,38011L,38012L,
8363038013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L,38021L,38022L,
8363138023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L,38031L,38032L,
8363238033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L,38041L,38042L,
8363338043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L,38051L,38052L,
8363438053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L,38061L,38062L,
8363538063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L,38071L,38072L,
8363638073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L,38081L,38082L,
8363738083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L,38091L,38092L,
8363838093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L,38101L,38102L,
8363938103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L,38111L,38112L,
8364038113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L,38121L,38122L,
8364138123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L,38131L,38132L,
8364238133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L,38141L,38142L,
8364338143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L,38151L,38152L,
8364438153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L,38161L,38162L,
8364538163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L,38171L,38172L,
8364638173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L,38181L,38182L,
8364738183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L,38191L,38192L,
8364838193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L,38201L,38202L,
8364938203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L,38211L,38212L,
8365038213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L,38221L,38222L,
8365138223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L,38231L,38232L,
8365238233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L,38241L,38242L,
8365338243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L,38251L,38252L,
8365438253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L,38261L,38262L,
8365538263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L,38271L,38272L,
8365638273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L,38281L,38282L,
8365738283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L,38291L,38292L,
8365838293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L,38301L,38302L,
8365938303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L,38311L,38312L,
8366038313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L,38321L,38322L,
8366138323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L,38331L,38332L,
8366238333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L,38341L,38342L,
8366338343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L,38351L,38352L,
8366438353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L,38361L,38362L,
8366538363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L,38371L,38372L,
8366638373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L,38381L,38382L,
8366738383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L,38391L,38392L,
8366838393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L,38401L,38402L,
8366938403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L,38411L,38412L,
8367038413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L,38421L,38422L,
8367138423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L,38431L,38432L,
8367238433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L,38441L,38442L,
8367338443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L,38451L,38452L,
8367438453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L,38461L,38462L,
8367538463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L,38471L,38472L,
8367638473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L,38481L,38482L,
8367738483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L,38491L,38492L,
8367838493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L,38501L,38502L,
8367938503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L,38511L,38512L,
8368038513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L,38521L,38522L,
8368138523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L,38531L,38532L,
8368238533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L,38541L,38542L,
8368338543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L,38551L,38552L,
8368438553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L,38561L,38562L,
8368538563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L,38571L,38572L,
8368638573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L,38581L,38582L,
8368738583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L,38591L,38592L,
8368838593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L,38601L,38602L,
8368938603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L,38611L,38612L,
8369038613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L,38621L,38622L,
8369138623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L,38631L,38632L,
8369238633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L,38641L,38642L,
8369338643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L,38651L,38652L,
8369438653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L,38661L,38662L,
8369538663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L,38671L,38672L,
8369638673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L,38681L,38682L,
8369738683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L,38691L,38692L,
8369838693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L,38701L,38702L,
8369938703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L,38711L,38712L,
8370038713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L,38721L,38722L,
8370138723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L,38731L,38732L,
8370238733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L,38741L,38742L,
8370338743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L,38751L,38752L,
8370438753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L,38761L,38762L,
8370538763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L,38771L,38772L,
8370638773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L,38781L,38782L,
8370738783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L,38791L,38792L,
8370838793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L,38801L,38802L,
8370938803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L,38811L,38812L,
8371038813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L,38821L,38822L,
8371138823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L,38831L,38832L,
8371238833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L,38841L,38842L,
8371338843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L,38851L,38852L,
8371438853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L,38861L,38862L,
8371538863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L,38871L,38872L,
8371638873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L,38881L,38882L,
8371738883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L,38891L,38892L,
8371838893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L,38901L,38902L,
8371938903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L,38911L,38912L,
8372038913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L,38921L,38922L,
8372138923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L,38931L,38932L,
8372238933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L,38941L,38942L,
8372338943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L,38951L,38952L,
8372438953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L,38961L,38962L,
8372538963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L,38971L,38972L,
8372638973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L,38981L,38982L,
8372738983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L,38991L,38992L,
8372838993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L,39001L,39002L,
8372939003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L,39011L,39012L,
8373039013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L,39021L,39022L,
8373139023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L,39031L,39032L,
8373239033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L,39041L,39042L,
8373339043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L,39051L,39052L,
8373439053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L,39061L,39062L,
8373539063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L,39071L,39072L,
8373639073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L,39081L,39082L,
8373739083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L,39091L,39092L,
8373839093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L,39101L,39102L,
8373939103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L,39111L,39112L,
8374039113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L,39121L,39122L,
8374139123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L,39131L,39132L,
8374239133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L,39141L,39142L,
8374339143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L,39151L,39152L,
8374439153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L,39161L,39162L,
8374539163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L,39171L,39172L,
8374639173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L,39181L,39182L,
8374739183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L,39191L,39192L,
8374839193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L,39201L,39202L,
8374939203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L,39211L,39212L,
8375039213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L,39221L,39222L,
8375139223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L,39231L,39232L,
8375239233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L,39241L,39242L,
8375339243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L,39251L,39252L,
8375439253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L,39261L,39262L,
8375539263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L,39271L,39272L,
8375639273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L,39281L,39282L,
8375739283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L,39291L,39292L,
8375839293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L,39301L,39302L,
8375939303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L,39311L,39312L,
8376039313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L,39321L,39322L,
8376139323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L,39331L,39332L,
8376239333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L,39341L,39342L,
8376339343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L,39351L,39352L,
8376439353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L,39361L,39362L,
8376539363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L,39371L,39372L,
8376639373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L,39381L,39382L,
8376739383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L,39391L,39392L,
8376839393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L,39401L,39402L,
8376939403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L,39411L,39412L,
8377039413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L,39421L,39422L,
8377139423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L,39431L,39432L,
8377239433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L,39441L,39442L,
8377339443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L,39451L,39452L,
8377439453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L,39461L,39462L,
8377539463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L,39471L,39472L,
8377639473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L,39481L,39482L,
8377739483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L,39491L,39492L,
8377839493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L,39501L,39502L,
8377939503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L,39511L,39512L,
8378039513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L,39521L,39522L,
8378139523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L,39531L,39532L,
8378239533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L,39541L,39542L,
8378339543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L,39551L,39552L,
8378439553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L,39561L,39562L,
8378539563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L,39571L,39572L,
8378639573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L,39581L,39582L,
8378739583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L,39591L,39592L,
8378839593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L,39601L,39602L,
8378939603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L,39611L,39612L,
8379039613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L,39621L,39622L,
8379139623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L,39631L,39632L,
8379239633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L,39641L,39642L,
8379339643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L,39651L,39652L,
8379439653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L,39661L,39662L,
8379539663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L,39671L,39672L,
8379639673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L,39681L,39682L,
8379739683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L,39691L,39692L,
8379839693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L,39701L,39702L,
8379939703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L,39711L,39712L,
8380039713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L,39721L,39722L,
8380139723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L,39731L,39732L,
8380239733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L,39741L,39742L,
8380339743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L,39751L,39752L,
8380439753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L,39761L,39762L,
8380539763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L,39771L,39772L,
8380639773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L,39781L,39782L,
8380739783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L,39791L,39792L,
8380839793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L,39801L,39802L,
8380939803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L,39811L,39812L,
8381039813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L,39821L,39822L,
8381139823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L,39831L,39832L,
8381239833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L,39841L,39842L,
8381339843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L,39851L,39852L,
8381439853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L,39861L,39862L,
8381539863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L,39871L,39872L,
8381639873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L,39881L,39882L,
8381739883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L,39891L,39892L,
8381839893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L,39901L,39902L,
8381939903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L,39911L,39912L,
8382039913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L,39921L,39922L,
8382139923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L,39931L,39932L,
8382239933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L,39941L,39942L,
8382339943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L,39951L,39952L,
8382439953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L,39961L,39962L,
8382539963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L,39971L,39972L,
8382639973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L,39981L,39982L,
8382739983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L,39991L,39992L,
8382839993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L,40001L,40002L,
8382940003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L,40011L,40012L,
8383040013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L,40021L,40022L,
8383140023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L,40031L,40032L,
8383240033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L,40041L,40042L,
8383340043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L,40051L,40052L,
8383440053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L,40061L,40062L,
8383540063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L,40071L,40072L,
8383640073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L,40081L,40082L,
8383740083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L,40091L,40092L,
8383840093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L,40101L,40102L,
8383940103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L,40111L,40112L,
8384040113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L,40121L,40122L,
8384140123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L,40131L,40132L,
8384240133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L,40141L,40142L,
8384340143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L,40151L,40152L,
8384440153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L,40161L,40162L,
8384540163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L,40171L,40172L,
8384640173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L,40181L,40182L,
8384740183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L,40191L,40192L,
8384840193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L,40201L,40202L,
8384940203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L,40211L,40212L,
8385040213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L,40221L,40222L,
8385140223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L,40231L,40232L,
8385240233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L,40241L,40242L,
8385340243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L,40251L,40252L,
8385440253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L,40261L,40262L,
8385540263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L,40271L,40272L,
8385640273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L,40281L,40282L,
8385740283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L,40291L,40292L,
8385840293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L,40301L,40302L,
8385940303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L,40311L,40312L,
8386040313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L,40321L,40322L,
8386140323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L,40331L,40332L,
8386240333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L,40341L,40342L,
8386340343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L,40351L,40352L,
8386440353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L,40361L,40362L,
8386540363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L,40371L,40372L,
8386640373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L,40381L,40382L,
8386740383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L,40391L,40392L,
8386840393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L,40401L,40402L,
8386940403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L,40411L,40412L,
8387040413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L,40421L,40422L,
8387140423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L,40431L,40432L,
8387240433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L,40441L,40442L,
8387340443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L,40451L,40452L,
8387440453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L,40461L,40462L,
8387540463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L,40471L,40472L,
8387640473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L,40481L,40482L,
8387740483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L,40491L,40492L,
8387840493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L,40501L,40502L,
8387940503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L,40511L,40512L,
8388040513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L,40521L,40522L,
8388140523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L,40531L,40532L,
8388240533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L,40541L,40542L,
8388340543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L,40551L,40552L,
8388440553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L,40561L,40562L,
8388540563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L,40571L,40572L,
8388640573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L,40581L,40582L,
8388740583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L,40591L,40592L,
8388840593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L,40601L,40602L,
8388940603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L,40611L,40612L,
8389040613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L,40621L,40622L,
8389140623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L,40631L,40632L,
8389240633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L,40641L,40642L,
8389340643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L,40651L,40652L,
8389440653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L,40661L,40662L,
8389540663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L,40671L,40672L,
8389640673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L,40681L,40682L,
8389740683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L,40691L,40692L,
8389840693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L,40701L,40702L,
8389940703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L,40711L,40712L,
8390040713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L,40721L,40722L,
8390140723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L,40731L,40732L,
8390240733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L,40741L,40742L,
8390340743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L,40751L,40752L,
8390440753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L,40761L,40762L,
8390540763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L,40771L,40772L,
8390640773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L,40781L,40782L,
8390740783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L,40791L,40792L,
8390840793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L,40801L,40802L,
8390940803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L,40811L,40812L,
8391040813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L,40821L,40822L,
8391140823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L,40831L,40832L,
8391240833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L,40841L,40842L,
8391340843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L,40851L,40852L,
8391440853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L,40861L,40862L,
8391540863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L,40871L,40872L,
8391640873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L,40881L,40882L,
8391740883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L,40891L,40892L,
8391840893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L,40901L,40902L,
8391940903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L,40911L,40912L,
8392040913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L,40921L,40922L,
8392140923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L,40931L,40932L,
8392240933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L,40941L,40942L,
8392340943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L,40951L,40952L,
8392440953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L,40961L,40962L,
8392540963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L,40971L,40972L,
8392640973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L,40981L,40982L,
8392740983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L,40991L,40992L,
8392840993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L,41001L,41002L,
8392941003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L,41011L,41012L,
8393041013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L,41021L,41022L,
8393141023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L,41031L,41032L,
8393241033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L,41041L,41042L,
8393341043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L,41051L,41052L,
8393441053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L,41061L,41062L,
8393541063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L,41071L,41072L,
8393641073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L,41081L,41082L,
8393741083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L,41091L,41092L,
8393841093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L,41101L,41102L,
8393941103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L,41111L,41112L,
8394041113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L,41121L,41122L,
8394141123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L,41131L,41132L,
8394241133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L,41141L,41142L,
8394341143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L,41151L,41152L,
8394441153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L,41161L,41162L,
8394541163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L,41171L,41172L,
8394641173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L,41181L,41182L,
8394741183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L,41191L,41192L,
8394841193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L,41201L,41202L,
8394941203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L,41211L,41212L,
8395041213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L,41221L,41222L,
8395141223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L,41231L,41232L,
8395241233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L,41241L,41242L,
8395341243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L,41251L,41252L,
8395441253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L,41261L,41262L,
8395541263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L,41271L,41272L,
8395641273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L,41281L,41282L,
8395741283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L,41291L,41292L,
8395841293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L,41301L,41302L,
8395941303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L,41311L,41312L,
8396041313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L,41321L,41322L,
8396141323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L,41331L,41332L,
8396241333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L,41341L,41342L,
8396341343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L,41351L,41352L,
8396441353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L,41361L,41362L,
8396541363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L,41371L,41372L,
8396641373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L,41381L,41382L,
8396741383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L,41391L,41392L,
8396841393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L,41401L,41402L,
8396941403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L,41411L,41412L,
8397041413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L,41421L,41422L,
8397141423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L,41431L,41432L,
8397241433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L,41441L,41442L,
8397341443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L,41451L,41452L,
8397441453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L,41461L,41462L,
8397541463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L,41471L,41472L,
8397641473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L,41481L,41482L,
8397741483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L,41491L,41492L,
8397841493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L,41501L,41502L,
8397941503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L,41511L,41512L,
8398041513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L,41521L,41522L,
8398141523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L,41531L,41532L,
8398241533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L,41541L,41542L,
8398341543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L,41551L,41552L,
8398441553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L,41561L,41562L,
8398541563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L,41571L,41572L,
8398641573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L,41581L,41582L,
8398741583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L,41591L,41592L,
8398841593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L,41601L,41602L,
8398941603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L,41611L,41612L,
8399041613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L,41621L,41622L,
8399141623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L,41631L,41632L,
8399241633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L,41641L,41642L,
8399341643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L,41651L,41652L,
8399441653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L,41661L,41662L,
8399541663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L,41671L,41672L,
8399641673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L,41681L,41682L,
8399741683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L,41691L,41692L,
8399841693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L,41701L,41702L,
8399941703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L,41711L,41712L,
8400041713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L,41721L,41722L,
8400141723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L,41731L,41732L,
8400241733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L,41741L,41742L,
8400341743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L,41751L,41752L,
8400441753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L,41761L,41762L,
8400541763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L,41771L,41772L,
8400641773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L,41781L,41782L,
8400741783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L,41791L,41792L,
8400841793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L,41801L,41802L,
8400941803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L,41811L,41812L,
8401041813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L,41821L,41822L,
8401141823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L,41831L,41832L,
8401241833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L,41841L,41842L,
8401341843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L,41851L,41852L,
8401441853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L,41861L,41862L,
8401541863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L,41871L,41872L,
8401641873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L,41881L,41882L,
8401741883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L,41891L,41892L,
8401841893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L,41901L,41902L,
8401941903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L,41911L,41912L,
8402041913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L,41921L,41922L,
8402141923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L,41931L,41932L,
8402241933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L,41941L,41942L,
8402341943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L,41951L,41952L,
8402441953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L,41961L,41962L,
8402541963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L,41971L,41972L,
8402641973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L,41981L,41982L,
8402741983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L,41991L,41992L,
8402841993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L,42001L,42002L,
8402942003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L,42011L,42012L,
8403042013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L,42021L,42022L,
8403142023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L,42031L,42032L,
8403242033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L,42041L,42042L,
8403342043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L,42051L,42052L,
8403442053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L,42061L,42062L,
8403542063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L,42071L,42072L,
8403642073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L,42081L,42082L,
8403742083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L,42091L,42092L,
8403842093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L,42101L,42102L,
8403942103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L,42111L,42112L,
8404042113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L,42121L,42122L,
8404142123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L,42131L,42132L,
8404242133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L,42141L,42142L,
8404342143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L,42151L,42152L,
8404442153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L,42161L,42162L,
8404542163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L,42171L,42172L,
8404642173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L,42181L,42182L,
8404742183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L,42191L,42192L,
8404842193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L,42201L,42202L,
8404942203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L,42211L,42212L,
8405042213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L,42221L,42222L,
8405142223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L,42231L,42232L,
8405242233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L,42241L,42242L,
8405342243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L,42251L,42252L,
8405442253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L,42261L,42262L,
8405542263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L,42271L,42272L,
8405642273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L,42281L,42282L,
8405742283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L,42291L,42292L,
8405842293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L,42301L,42302L,
8405942303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L,42311L,42312L,
8406042313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L,42321L,42322L,
8406142323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L,42331L,42332L,
8406242333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L,42341L,42342L,
8406342343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L,42351L,42352L,
8406442353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L,42361L,42362L,
8406542363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L,42371L,42372L,
8406642373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L,42381L,42382L,
8406742383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L,42391L,42392L,
8406842393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L,42401L,42402L,
8406942403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L,42411L,42412L,
8407042413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L,42421L,42422L,
8407142423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L,42431L,42432L,
8407242433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L,42441L,42442L,
8407342443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L,42451L,42452L,
8407442453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L,42461L,42462L,
8407542463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L,42471L,42472L,
8407642473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L,42481L,42482L,
8407742483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L,42491L,42492L,
8407842493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L,42501L,42502L,
8407942503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L,42511L,42512L,
8408042513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L,42521L,42522L,
8408142523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L,42531L,42532L,
8408242533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L,42541L,42542L,
8408342543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L,42551L,42552L,
8408442553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L,42560L,42562L,
8408542562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L,42570L,42572L,
8408642572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L,42580L,42582L,
8408742582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L,42590L,42592L,
8408842592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L,42600L,42602L,
8408942602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L,42611L,42612L,
8409042613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L,42621L,42622L,
8409142623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L,42630L,42632L,
8409242632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L,42640L,42642L,
8409342642L,42644L,42644L,42646L,42646L,42648L,42649L,42650L,42651L,42652L,
8409442653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L,42661L,42662L,
8409542663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L,42671L,42672L,
8409642673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L,42681L,42682L,
8409742683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L,42691L,42692L,
8409842693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L,42701L,42702L,
8409942703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L,42711L,42712L,
8410042713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L,42721L,42722L,
8410142723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L,42731L,42732L,
8410242733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L,42741L,42742L,
8410342743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L,42751L,42752L,
8410442753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L,42761L,42762L,
8410542763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L,42771L,42772L,
8410642773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L,42781L,42782L,
8410742783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L,42790L,42792L,
8410842792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L,42801L,42802L,
8410942802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L,42810L,42812L,
8411042812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L,42820L,42822L,
8411142822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L,42830L,42832L,
8411242832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L,42840L,42842L,
8411342842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L,42850L,42852L,
8411442852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L,42860L,42862L,
8411542862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L,42871L,42872L,
8411642873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L,42880L,42882L,
8411742882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L,42891L,42891L,
8411842893L,42894L,42895L,42896L,42896L,42898L,42899L,42900L,42901L,42902L,
8411942903L,42904L,42905L,42906L,42907L,42908L,42909L,42910L,42911L,42912L,
8412042912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L,42920L,42922L,
8412142923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L,42931L,42932L,
8412242933L,42934L,42935L,42936L,42937L,42938L,42939L,42940L,42941L,42942L,
8412342943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L,42951L,42952L,
8412442953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L,42961L,42962L,
8412542963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L,42971L,42972L,
8412642973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L,42981L,42982L,
8412742983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L,42991L,42992L,
8412842993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L,43001L,43002L,
8412943003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L,43011L,43012L,
8413043013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L,43021L,43022L,
8413143023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L,43031L,43032L,
8413243033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L,43041L,43042L,
8413343043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L,43051L,43052L,
8413443053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L,43061L,43062L,
8413543063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L,43071L,43072L,
8413643073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L,43081L,43082L,
8413743083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L,43091L,43092L,
8413843093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L,43101L,43102L,
8413943103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L,43111L,43112L,
8414043113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L,43121L,43122L,
8414143123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L,43131L,43132L,
8414243133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L,43141L,43142L,
8414343143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L,43151L,43152L,
8414443153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L,43161L,43162L,
8414543163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L,43171L,43172L,
8414643173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L,43181L,43182L,
8414743183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L,43191L,43192L,
8414843193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L,43201L,43202L,
8414943203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L,43211L,43212L,
8415043213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L,43221L,43222L,
8415143223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L,43231L,43232L,
8415243233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L,43241L,43242L,
8415343243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L,43251L,43252L,
8415443253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L,43261L,43262L,
8415543263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L,43271L,43272L,
8415643273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L,43281L,43282L,
8415743283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L,43291L,43292L,
8415843293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L,43301L,43302L,
8415943303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L,43311L,43312L,
8416043313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L,43321L,43322L,
8416143323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L,43331L,43332L,
8416243333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L,43341L,43342L,
8416343343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L,43351L,43352L,
8416443353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L,43361L,43362L,
8416543363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L,43371L,43372L,
8416643373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L,43381L,43382L,
8416743383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L,43391L,43392L,
8416843393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L,43401L,43402L,
8416943403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L,43411L,43412L,
8417043413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L,43421L,43422L,
8417143423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L,43431L,43432L,
8417243433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L,43441L,43442L,
8417343443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L,43451L,43452L,
8417443453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L,43461L,43462L,
8417543463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L,43471L,43472L,
8417643473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L,43481L,43482L,
8417743483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L,43491L,43492L,
8417843493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L,43501L,43502L,
8417943503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L,43511L,43512L,
8418043513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L,43521L,43522L,
8418143523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L,43531L,43532L,
8418243533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L,43541L,43542L,
8418343543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L,43551L,43552L,
8418443553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L,43561L,43562L,
8418543563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L,43571L,43572L,
8418643573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L,43581L,43582L,
8418743583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L,43591L,43592L,
8418843593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L,43601L,43602L,
8418943603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L,43611L,43612L,
8419043613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L,43621L,43622L,
8419143623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L,43631L,43632L,
8419243633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L,43641L,43642L,
8419343643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L,43651L,43652L,
8419443653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L,43661L,43662L,
8419543663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L,43671L,43672L,
8419643673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L,43681L,43682L,
8419743683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L,43691L,43692L,
8419843693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L,43701L,43702L,
8419943703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L,43711L,43712L,
8420043713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L,43721L,43722L,
8420143723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L,43731L,43732L,
8420243733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L,43741L,43742L,
8420343743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L,43751L,43752L,
8420443753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L,43761L,43762L,
8420543763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L,43771L,43772L,
8420643773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L,43781L,43782L,
8420743783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L,43791L,43792L,
8420843793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L,43801L,43802L,
8420943803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L,43811L,43812L,
8421043813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L,43821L,43822L,
8421143823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L,43831L,43832L,
8421243833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L,43841L,43842L,
8421343843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L,43851L,43852L,
8421443853L,43854L,43855L,43856L,43857L,43858L,43859L,43860L,43861L,43862L,
8421543863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L,43871L,43872L,
8421643873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L,43881L,43882L,
8421743883L,43884L,43885L,43886L,43887L,43888L,43889L,43890L,43891L,43892L,
8421843893L,43894L,43895L,43896L,43897L,43898L,43899L,43900L,43901L,43902L,
8421943903L,43904L,43905L,43906L,43907L,43908L,43909L,43910L,43911L,43912L,
8422043913L,43914L,43915L,43916L,43917L,43918L,43919L,43920L,43921L,43922L,
8422143923L,43924L,43925L,43926L,43927L,43928L,43929L,43930L,43931L,43932L,
8422243933L,43934L,43935L,43936L,43937L,43938L,43939L,43940L,43941L,43942L,
8422343943L,43944L,43945L,43946L,43947L,43948L,43949L,43950L,43951L,43952L,
8422443953L,43954L,43955L,43956L,43957L,43958L,43959L,43960L,43961L,43962L,
8422543963L,43964L,43965L,43966L,43967L,43968L,43969L,43970L,43971L,43972L,
8422643973L,43974L,43975L,43976L,43977L,43978L,43979L,43980L,43981L,43982L,
8422743983L,43984L,43985L,43986L,43987L,43988L,43989L,43990L,43991L,43992L,
8422843993L,43994L,43995L,43996L,43997L,43998L,43999L,44000L,44001L,44002L,
8422944003L,44004L,44005L,44006L,44007L,44008L,44009L,44010L,44011L,44012L,
8423044013L,44014L,44015L,44016L,44017L,44018L,44019L,44020L,44021L,44022L,
8423144023L,44024L,44025L,44026L,44027L,44028L,44029L,44030L,44031L,44032L,
8423244033L,44034L,44035L,44036L,44037L,44038L,44039L,44040L,44041L,44042L,
8423344043L,44044L,44045L,44046L,44047L,44048L,44049L,44050L,44051L,44052L,
8423444053L,44054L,44055L,44056L,44057L,44058L,44059L,44060L,44061L,44062L,
8423544063L,44064L,44065L,44066L,44067L,44068L,44069L,44070L,44071L,44072L,
8423644073L,44074L,44075L,44076L,44077L,44078L,44079L,44080L,44081L,44082L,
8423744083L,44084L,44085L,44086L,44087L,44088L,44089L,44090L,44091L,44092L,
8423844093L,44094L,44095L,44096L,44097L,44098L,44099L,44100L,44101L,44102L,
8423944103L,44104L,44105L,44106L,44107L,44108L,44109L,44110L,44111L,44112L,
8424044113L,44114L,44115L,44116L,44117L,44118L,44119L,44120L,44121L,44122L,
8424144123L,44124L,44125L,44126L,44127L,44128L,44129L,44130L,44131L,44132L,
8424244133L,44134L,44135L,44136L,44137L,44138L,44139L,44140L,44141L,44142L,
8424344143L,44144L,44145L,44146L,44147L,44148L,44149L,44150L,44151L,44152L,
8424444153L,44154L,44155L,44156L,44157L,44158L,44159L,44160L,44161L,44162L,
8424544163L,44164L,44165L,44166L,44167L,44168L,44169L,44170L,44171L,44172L,
8424644173L,44174L,44175L,44176L,44177L,44178L,44179L,44180L,44181L,44182L,
8424744183L,44184L,44185L,44186L,44187L,44188L,44189L,44190L,44191L,44192L,
8424844193L,44194L,44195L,44196L,44197L,44198L,44199L,44200L,44201L,44202L,
8424944203L,44204L,44205L,44206L,44207L,44208L,44209L,44210L,44211L,44212L,
8425044213L,44214L,44215L,44216L,44217L,44218L,44219L,44220L,44221L,44222L,
8425144223L,44224L,44225L,44226L,44227L,44228L,44229L,44230L,44231L,44232L,
8425244233L,44234L,44235L,44236L,44237L,44238L,44239L,44240L,44241L,44242L,
8425344243L,44244L,44245L,44246L,44247L,44248L,44249L,44250L,44251L,44252L,
8425444253L,44254L,44255L,44256L,44257L,44258L,44259L,44260L,44261L,44262L,
8425544263L,44264L,44265L,44266L,44267L,44268L,44269L,44270L,44271L,44272L,
8425644273L,44274L,44275L,44276L,44277L,44278L,44279L,44280L,44281L,44282L,
8425744283L,44284L,44285L,44286L,44287L,44288L,44289L,44290L,44291L,44292L,
8425844293L,44294L,44295L,44296L,44297L,44298L,44299L,44300L,44301L,44302L,
8425944303L,44304L,44305L,44306L,44307L,44308L,44309L,44310L,44311L,44312L,
8426044313L,44314L,44315L,44316L,44317L,44318L,44319L,44320L,44321L,44322L,
8426144323L,44324L,44325L,44326L,44327L,44328L,44329L,44330L,44331L,44332L,
8426244333L,44334L,44335L,44336L,44337L,44338L,44339L,44340L,44341L,44342L,
8426344343L,44344L,44345L,44346L,44347L,44348L,44349L,44350L,44351L,44352L,
8426444353L,44354L,44355L,44356L,44357L,44358L,44359L,44360L,44361L,44362L,
8426544363L,44364L,44365L,44366L,44367L,44368L,44369L,44370L,44371L,44372L,
8426644373L,44374L,44375L,44376L,44377L,44378L,44379L,44380L,44381L,44382L,
8426744383L,44384L,44385L,44386L,44387L,44388L,44389L,44390L,44391L,44392L,
8426844393L,44394L,44395L,44396L,44397L,44398L,44399L,44400L,44401L,44402L,
8426944403L,44404L,44405L,44406L,44407L,44408L,44409L,44410L,44411L,44412L,
8427044413L,44414L,44415L,44416L,44417L,44418L,44419L,44420L,44421L,44422L,
8427144423L,44424L,44425L,44426L,44427L,44428L,44429L,44430L,44431L,44432L,
8427244433L,44434L,44435L,44436L,44437L,44438L,44439L,44440L,44441L,44442L,
8427344443L,44444L,44445L,44446L,44447L,44448L,44449L,44450L,44451L,44452L,
8427444453L,44454L,44455L,44456L,44457L,44458L,44459L,44460L,44461L,44462L,
8427544463L,44464L,44465L,44466L,44467L,44468L,44469L,44470L,44471L,44472L,
8427644473L,44474L,44475L,44476L,44477L,44478L,44479L,44480L,44481L,44482L,
8427744483L,44484L,44485L,44486L,44487L,44488L,44489L,44490L,44491L,44492L,
8427844493L,44494L,44495L,44496L,44497L,44498L,44499L,44500L,44501L,44502L,
8427944503L,44504L,44505L,44506L,44507L,44508L,44509L,44510L,44511L,44512L,
8428044513L,44514L,44515L,44516L,44517L,44518L,44519L,44520L,44521L,44522L,
8428144523L,44524L,44525L,44526L,44527L,44528L,44529L,44530L,44531L,44532L,
8428244533L,44534L,44535L,44536L,44537L,44538L,44539L,44540L,44541L,44542L,
8428344543L,44544L,44545L,44546L,44547L,44548L,44549L,44550L,44551L,44552L,
8428444553L,44554L,44555L,44556L,44557L,44558L,44559L,44560L,44561L,44562L,
8428544563L,44564L,44565L,44566L,44567L,44568L,44569L,44570L,44571L,44572L,
8428644573L,44574L,44575L,44576L,44577L,44578L,44579L,44580L,44581L,44582L,
8428744583L,44584L,44585L,44586L,44587L,44588L,44589L,44590L,44591L,44592L,
8428844593L,44594L,44595L,44596L,44597L,44598L,44599L,44600L,44601L,44602L,
8428944603L,44604L,44605L,44606L,44607L,44608L,44609L,44610L,44611L,44612L,
8429044613L,44614L,44615L,44616L,44617L,44618L,44619L,44620L,44621L,44622L,
8429144623L,44624L,44625L,44626L,44627L,44628L,44629L,44630L,44631L,44632L,
8429244633L,44634L,44635L,44636L,44637L,44638L,44639L,44640L,44641L,44642L,
8429344643L,44644L,44645L,44646L,44647L,44648L,44649L,44650L,44651L,44652L,
8429444653L,44654L,44655L,44656L,44657L,44658L,44659L,44660L,44661L,44662L,
8429544663L,44664L,44665L,44666L,44667L,44668L,44669L,44670L,44671L,44672L,
8429644673L,44674L,44675L,44676L,44677L,44678L,44679L,44680L,44681L,44682L,
8429744683L,44684L,44685L,44686L,44687L,44688L,44689L,44690L,44691L,44692L,
8429844693L,44694L,44695L,44696L,44697L,44698L,44699L,44700L,44701L,44702L,
8429944703L,44704L,44705L,44706L,44707L,44708L,44709L,44710L,44711L,44712L,
8430044713L,44714L,44715L,44716L,44717L,44718L,44719L,44720L,44721L,44722L,
8430144723L,44724L,44725L,44726L,44727L,44728L,44729L,44730L,44731L,44732L,
8430244733L,44734L,44735L,44736L,44737L,44738L,44739L,44740L,44741L,44742L,
8430344743L,44744L,44745L,44746L,44747L,44748L,44749L,44750L,44751L,44752L,
8430444753L,44754L,44755L,44756L,44757L,44758L,44759L,44760L,44761L,44762L,
8430544763L,44764L,44765L,44766L,44767L,44768L,44769L,44770L,44771L,44772L,
8430644773L,44774L,44775L,44776L,44777L,44778L,44779L,44780L,44781L,44782L,
8430744783L,44784L,44785L,44786L,44787L,44788L,44789L,44790L,44791L,44792L,
8430844793L,44794L,44795L,44796L,44797L,44798L,44799L,44800L,44801L,44802L,
8430944803L,44804L,44805L,44806L,44807L,44808L,44809L,44810L,44811L,44812L,
8431044813L,44814L,44815L,44816L,44817L,44818L,44819L,44820L,44821L,44822L,
8431144823L,44824L,44825L,44826L,44827L,44828L,44829L,44830L,44831L,44832L,
8431244833L,44834L,44835L,44836L,44837L,44838L,44839L,44840L,44841L,44842L,
8431344843L,44844L,44845L,44846L,44847L,44848L,44849L,44850L,44851L,44852L,
8431444853L,44854L,44855L,44856L,44857L,44858L,44859L,44860L,44861L,44862L,
8431544863L,44864L,44865L,44866L,44867L,44868L,44869L,44870L,44871L,44872L,
8431644873L,44874L,44875L,44876L,44877L,44878L,44879L,44880L,44881L,44882L,
8431744883L,44884L,44885L,44886L,44887L,44888L,44889L,44890L,44891L,44892L,
8431844893L,44894L,44895L,44896L,44897L,44898L,44899L,44900L,44901L,44902L,
8431944903L,44904L,44905L,44906L,44907L,44908L,44909L,44910L,44911L,44912L,
8432044913L,44914L,44915L,44916L,44917L,44918L,44919L,44920L,44921L,44922L,
8432144923L,44924L,44925L,44926L,44927L,44928L,44929L,44930L,44931L,44932L,
8432244933L,44934L,44935L,44936L,44937L,44938L,44939L,44940L,44941L,44942L,
8432344943L,44944L,44945L,44946L,44947L,44948L,44949L,44950L,44951L,44952L,
8432444953L,44954L,44955L,44956L,44957L,44958L,44959L,44960L,44961L,44962L,
8432544963L,44964L,44965L,44966L,44967L,44968L,44969L,44970L,44971L,44972L,
8432644973L,44974L,44975L,44976L,44977L,44978L,44979L,44980L,44981L,44982L,
8432744983L,44984L,44985L,44986L,44987L,44988L,44989L,44990L,44991L,44992L,
8432844993L,44994L,44995L,44996L,44997L,44998L,44999L,45000L,45001L,45002L,
8432945003L,45004L,45005L,45006L,45007L,45008L,45009L,45010L,45011L,45012L,
8433045013L,45014L,45015L,45016L,45017L,45018L,45019L,45020L,45021L,45022L,
8433145023L,45024L,45025L,45026L,45027L,45028L,45029L,45030L,45031L,45032L,
8433245033L,45034L,45035L,45036L,45037L,45038L,45039L,45040L,45041L,45042L,
8433345043L,45044L,45045L,45046L,45047L,45048L,45049L,45050L,45051L,45052L,
8433445053L,45054L,45055L,45056L,45057L,45058L,45059L,45060L,45061L,45062L,
8433545063L,45064L,45065L,45066L,45067L,45068L,45069L,45070L,45071L,45072L,
8433645073L,45074L,45075L,45076L,45077L,45078L,45079L,45080L,45081L,45082L,
8433745083L,45084L,45085L,45086L,45087L,45088L,45089L,45090L,45091L,45092L,
8433845093L,45094L,45095L,45096L,45097L,45098L,45099L,45100L,45101L,45102L,
8433945103L,45104L,45105L,45106L,45107L,45108L,45109L,45110L,45111L,45112L,
8434045113L,45114L,45115L,45116L,45117L,45118L,45119L,45120L,45121L,45122L,
8434145123L,45124L,45125L,45126L,45127L,45128L,45129L,45130L,45131L,45132L,
8434245133L,45134L,45135L,45136L,45137L,45138L,45139L,45140L,45141L,45142L,
8434345143L,45144L,45145L,45146L,45147L,45148L,45149L,45150L,45151L,45152L,
8434445153L,45154L,45155L,45156L,45157L,45158L,45159L,45160L,45161L,45162L,
8434545163L,45164L,45165L,45166L,45167L,45168L,45169L,45170L,45171L,45172L,
8434645173L,45174L,45175L,45176L,45177L,45178L,45179L,45180L,45181L,45182L,
8434745183L,45184L,45185L,45186L,45187L,45188L,45189L,45190L,45191L,45192L,
8434845193L,45194L,45195L,45196L,45197L,45198L,45199L,45200L,45201L,45202L,
8434945203L,45204L,45205L,45206L,45207L,45208L,45209L,45210L,45211L,45212L,
8435045213L,45214L,45215L,45216L,45217L,45218L,45219L,45220L,45221L,45222L,
8435145223L,45224L,45225L,45226L,45227L,45228L,45229L,45230L,45231L,45232L,
8435245233L,45234L,45235L,45236L,45237L,45238L,45239L,45240L,45241L,45242L,
8435345243L,45244L,45245L,45246L,45247L,45248L,45249L,45250L,45251L,45252L,
8435445253L,45254L,45255L,45256L,45257L,45258L,45259L,45260L,45261L,45262L,
8435545263L,45264L,45265L,45266L,45267L,45268L,45269L,45270L,45271L,45272L,
8435645273L,45274L,45275L,45276L,45277L,45278L,45279L,45280L,45281L,45282L,
8435745283L,45284L,45285L,45286L,45287L,45288L,45289L,45290L,45291L,45292L,
8435845293L,45294L,45295L,45296L,45297L,45298L,45299L,45300L,45301L,45302L,
8435945303L,45304L,45305L,45306L,45307L,45308L,45309L,45310L,45311L,45312L,
8436045313L,45314L,45315L,45316L,45317L,45318L,45319L,45320L,45321L,45322L,
8436145323L,45324L,45325L,45326L,45327L,45328L,45329L,45330L,45331L,45332L,
8436245333L,45334L,45335L,45336L,45337L,45338L,45339L,45340L,45341L,45342L,
8436345343L,45344L,45345L,45346L,45347L,45348L,45349L,45350L,45351L,45352L,
8436445353L,45354L,45355L,45356L,45357L,45358L,45359L,45360L,45361L,45362L,
8436545363L,45364L,45365L,45366L,45367L,45368L,45369L,45370L,45371L,45372L,
8436645373L,45374L,45375L,45376L,45377L,45378L,45379L,45380L,45381L,45382L,
8436745383L,45384L,45385L,45386L,45387L,45388L,45389L,45390L,45391L,45392L,
8436845393L,45394L,45395L,45396L,45397L,45398L,45399L,45400L,45401L,45402L,
8436945403L,45404L,45405L,45406L,45407L,45408L,45409L,45410L,45411L,45412L,
8437045413L,45414L,45415L,45416L,45417L,45418L,45419L,45420L,45421L,45422L,
8437145423L,45424L,45425L,45426L,45427L,45428L,45429L,45430L,45431L,45432L,
8437245433L,45434L,45435L,45436L,45437L,45438L,45439L,45440L,45441L,45442L,
8437345443L,45444L,45445L,45446L,45447L,45448L,45449L,45450L,45451L,45452L,
8437445453L,45454L,45455L,45456L,45457L,45458L,45459L,45460L,45461L,45462L,
8437545463L,45464L,45465L,45466L,45467L,45468L,45469L,45470L,45471L,45472L,
8437645473L,45474L,45475L,45476L,45477L,45478L,45479L,45480L,45481L,45482L,
8437745483L,45484L,45485L,45486L,45487L,45488L,45489L,45490L,45491L,45492L,
8437845493L,45494L,45495L,45496L,45497L,45498L,45499L,45500L,45501L,45502L,
8437945503L,45504L,45505L,45506L,45507L,45508L,45509L,45510L,45511L,45512L,
8438045513L,45514L,45515L,45516L,45517L,45518L,45519L,45520L,45521L,45522L,
8438145523L,45524L,45525L,45526L,45527L,45528L,45529L,45530L,45531L,45532L,
8438245533L,45534L,45535L,45536L,45537L,45538L,45539L,45540L,45541L,45542L,
8438345543L,45544L,45545L,45546L,45547L,45548L,45549L,45550L,45551L,45552L,
8438445553L,45554L,45555L,45556L,45557L,45558L,45559L,45560L,45561L,45562L,
8438545563L,45564L,45565L,45566L,45567L,45568L,45569L,45570L,45571L,45572L,
8438645573L,45574L,45575L,45576L,45577L,45578L,45579L,45580L,45581L,45582L,
8438745583L,45584L,45585L,45586L,45587L,45588L,45589L,45590L,45591L,45592L,
8438845593L,45594L,45595L,45596L,45597L,45598L,45599L,45600L,45601L,45602L,
8438945603L,45604L,45605L,45606L,45607L,45608L,45609L,45610L,45611L,45612L,
8439045613L,45614L,45615L,45616L,45617L,45618L,45619L,45620L,45621L,45622L,
8439145623L,45624L,45625L,45626L,45627L,45628L,45629L,45630L,45631L,45632L,
8439245633L,45634L,45635L,45636L,45637L,45638L,45639L,45640L,45641L,45642L,
8439345643L,45644L,45645L,45646L,45647L,45648L,45649L,45650L,45651L,45652L,
8439445653L,45654L,45655L,45656L,45657L,45658L,45659L,45660L,45661L,45662L,
8439545663L,45664L,45665L,45666L,45667L,45668L,45669L,45670L,45671L,45672L,
8439645673L,45674L,45675L,45676L,45677L,45678L,45679L,45680L,45681L,45682L,
8439745683L,45684L,45685L,45686L,45687L,45688L,45689L,45690L,45691L,45692L,
8439845693L,45694L,45695L,45696L,45697L,45698L,45699L,45700L,45701L,45702L,
8439945703L,45704L,45705L,45706L,45707L,45708L,45709L,45710L,45711L,45712L,
8440045713L,45714L,45715L,45716L,45717L,45718L,45719L,45720L,45721L,45722L,
8440145723L,45724L,45725L,45726L,45727L,45728L,45729L,45730L,45731L,45732L,
8440245733L,45734L,45735L,45736L,45737L,45738L,45739L,45740L,45741L,45742L,
8440345743L,45744L,45745L,45746L,45747L,45748L,45749L,45750L,45751L,45752L,
8440445753L,45754L,45755L,45756L,45757L,45758L,45759L,45760L,45761L,45762L,
8440545763L,45764L,45765L,45766L,45767L,45768L,45769L,45770L,45771L,45772L,
8440645773L,45774L,45775L,45776L,45777L,45778L,45779L,45780L,45781L,45782L,
8440745783L,45784L,45785L,45786L,45787L,45788L,45789L,45790L,45791L,45792L,
8440845793L,45794L,45795L,45796L,45797L,45798L,45799L,45800L,45801L,45802L,
8440945803L,45804L,45805L,45806L,45807L,45808L,45809L,45810L,45811L,45812L,
8441045813L,45814L,45815L,45816L,45817L,45818L,45819L,45820L,45821L,45822L,
8441145823L,45824L,45825L,45826L,45827L,45828L,45829L,45830L,45831L,45832L,
8441245833L,45834L,45835L,45836L,45837L,45838L,45839L,45840L,45841L,45842L,
8441345843L,45844L,45845L,45846L,45847L,45848L,45849L,45850L,45851L,45852L,
8441445853L,45854L,45855L,45856L,45857L,45858L,45859L,45860L,45861L,45862L,
8441545863L,45864L,45865L,45866L,45867L,45868L,45869L,45870L,45871L,45872L,
8441645873L,45874L,45875L,45876L,45877L,45878L,45879L,45880L,45881L,45882L,
8441745883L,45884L,45885L,45886L,45887L,45888L,45889L,45890L,45891L,45892L,
8441845893L,45894L,45895L,45896L,45897L,45898L,45899L,45900L,45901L,45902L,
8441945903L,45904L,45905L,45906L,45907L,45908L,45909L,45910L,45911L,45912L,
8442045913L,45914L,45915L,45916L,45917L,45918L,45919L,45920L,45921L,45922L,
8442145923L,45924L,45925L,45926L,45927L,45928L,45929L,45930L,45931L,45932L,
8442245933L,45934L,45935L,45936L,45937L,45938L,45939L,45940L,45941L,45942L,
8442345943L,45944L,45945L,45946L,45947L,45948L,45949L,45950L,45951L,45952L,
8442445953L,45954L,45955L,45956L,45957L,45958L,45959L,45960L,45961L,45962L,
8442545963L,45964L,45965L,45966L,45967L,45968L,45969L,45970L,45971L,45972L,
8442645973L,45974L,45975L,45976L,45977L,45978L,45979L,45980L,45981L,45982L,
8442745983L,45984L,45985L,45986L,45987L,45988L,45989L,45990L,45991L,45992L,
8442845993L,45994L,45995L,45996L,45997L,45998L,45999L,46000L,46001L,46002L,
8442946003L,46004L,46005L,46006L,46007L,46008L,46009L,46010L,46011L,46012L,
8443046013L,46014L,46015L,46016L,46017L,46018L,46019L,46020L,46021L,46022L,
8443146023L,46024L,46025L,46026L,46027L,46028L,46029L,46030L,46031L,46032L,
8443246033L,46034L,46035L,46036L,46037L,46038L,46039L,46040L,46041L,46042L,
8443346043L,46044L,46045L,46046L,46047L,46048L,46049L,46050L,46051L,46052L,
8443446053L,46054L,46055L,46056L,46057L,46058L,46059L,46060L,46061L,46062L,
8443546063L,46064L,46065L,46066L,46067L,46068L,46069L,46070L,46071L,46072L,
8443646073L,46074L,46075L,46076L,46077L,46078L,46079L,46080L,46081L,46082L,
8443746083L,46084L,46085L,46086L,46087L,46088L,46089L,46090L,46091L,46092L,
8443846093L,46094L,46095L,46096L,46097L,46098L,46099L,46100L,46101L,46102L,
8443946103L,46104L,46105L,46106L,46107L,46108L,46109L,46110L,46111L,46112L,
8444046113L,46114L,46115L,46116L,46117L,46118L,46119L,46120L,46121L,46122L,
8444146123L,46124L,46125L,46126L,46127L,46128L,46129L,46130L,46131L,46132L,
8444246133L,46134L,46135L,46136L,46137L,46138L,46139L,46140L,46141L,46142L,
8444346143L,46144L,46145L,46146L,46147L,46148L,46149L,46150L,46151L,46152L,
8444446153L,46154L,46155L,46156L,46157L,46158L,46159L,46160L,46161L,46162L,
8444546163L,46164L,46165L,46166L,46167L,46168L,46169L,46170L,46171L,46172L,
8444646173L,46174L,46175L,46176L,46177L,46178L,46179L,46180L,46181L,46182L,
8444746183L,46184L,46185L,46186L,46187L,46188L,46189L,46190L,46191L,46192L,
8444846193L,46194L,46195L,46196L,46197L,46198L,46199L,46200L,46201L,46202L,
8444946203L,46204L,46205L,46206L,46207L,46208L,46209L,46210L,46211L,46212L,
8445046213L,46214L,46215L,46216L,46217L,46218L,46219L,46220L,46221L,46222L,
8445146223L,46224L,46225L,46226L,46227L,46228L,46229L,46230L,46231L,46232L,
8445246233L,46234L,46235L,46236L,46237L,46238L,46239L,46240L,46241L,46242L,
8445346243L,46244L,46245L,46246L,46247L,46248L,46249L,46250L,46251L,46252L,
8445446253L,46254L,46255L,46256L,46257L,46258L,46259L,46260L,46261L,46262L,
8445546263L,46264L,46265L,46266L,46267L,46268L,46269L,46270L,46271L,46272L,
8445646273L,46274L,46275L,46276L,46277L,46278L,46279L,46280L,46281L,46282L,
8445746283L,46284L,46285L,46286L,46287L,46288L,46289L,46290L,46291L,46292L,
8445846293L,46294L,46295L,46296L,46297L,46298L,46299L,46300L,46301L,46302L,
8445946303L,46304L,46305L,46306L,46307L,46308L,46309L,46310L,46311L,46312L,
8446046313L,46314L,46315L,46316L,46317L,46318L,46319L,46320L,46321L,46322L,
8446146323L,46324L,46325L,46326L,46327L,46328L,46329L,46330L,46331L,46332L,
8446246333L,46334L,46335L,46336L,46337L,46338L,46339L,46340L,46341L,46342L,
8446346343L,46344L,46345L,46346L,46347L,46348L,46349L,46350L,46351L,46352L,
8446446353L,46354L,46355L,46356L,46357L,46358L,46359L,46360L,46361L,46362L,
8446546363L,46364L,46365L,46366L,46367L,46368L,46369L,46370L,46371L,46372L,
8446646373L,46374L,46375L,46376L,46377L,46378L,46379L,46380L,46381L,46382L,
8446746383L,46384L,46385L,46386L,46387L,46388L,46389L,46390L,46391L,46392L,
8446846393L,46394L,46395L,46396L,46397L,46398L,46399L,46400L,46401L,46402L,
8446946403L,46404L,46405L,46406L,46407L,46408L,46409L,46410L,46411L,46412L,
8447046413L,46414L,46415L,46416L,46417L,46418L,46419L,46420L,46421L,46422L,
8447146423L,46424L,46425L,46426L,46427L,46428L,46429L,46430L,46431L,46432L,
8447246433L,46434L,46435L,46436L,46437L,46438L,46439L,46440L,46441L,46442L,
8447346443L,46444L,46445L,46446L,46447L,46448L,46449L,46450L,46451L,46452L,
8447446453L,46454L,46455L,46456L,46457L,46458L,46459L,46460L,46461L,46462L,
8447546463L,46464L,46465L,46466L,46467L,46468L,46469L,46470L,46471L,46472L,
8447646473L,46474L,46475L,46476L,46477L,46478L,46479L,46480L,46481L,46482L,
8447746483L,46484L,46485L,46486L,46487L,46488L,46489L,46490L,46491L,46492L,
8447846493L,46494L,46495L,46496L,46497L,46498L,46499L,46500L,46501L,46502L,
8447946503L,46504L,46505L,46506L,46507L,46508L,46509L,46510L,46511L,46512L,
8448046513L,46514L,46515L,46516L,46517L,46518L,46519L,46520L,46521L,46522L,
8448146523L,46524L,46525L,46526L,46527L,46528L,46529L,46530L,46531L,46532L,
8448246533L,46534L,46535L,46536L,46537L,46538L,46539L,46540L,46541L,46542L,
8448346543L,46544L,46545L,46546L,46547L,46548L,46549L,46550L,46551L,46552L,
8448446553L,46554L,46555L,46556L,46557L,46558L,46559L,46560L,46561L,46562L,
8448546563L,46564L,46565L,46566L,46567L,46568L,46569L,46570L,46571L,46572L,
8448646573L,46574L,46575L,46576L,46577L,46578L,46579L,46580L,46581L,46582L,
8448746583L,46584L,46585L,46586L,46587L,46588L,46589L,46590L,46591L,46592L,
8448846593L,46594L,46595L,46596L,46597L,46598L,46599L,46600L,46601L,46602L,
8448946603L,46604L,46605L,46606L,46607L,46608L,46609L,46610L,46611L,46612L,
8449046613L,46614L,46615L,46616L,46617L,46618L,46619L,46620L,46621L,46622L,
8449146623L,46624L,46625L,46626L,46627L,46628L,46629L,46630L,46631L,46632L,
8449246633L,46634L,46635L,46636L,46637L,46638L,46639L,46640L,46641L,46642L,
8449346643L,46644L,46645L,46646L,46647L,46648L,46649L,46650L,46651L,46652L,
8449446653L,46654L,46655L,46656L,46657L,46658L,46659L,46660L,46661L,46662L,
8449546663L,46664L,46665L,46666L,46667L,46668L,46669L,46670L,46671L,46672L,
8449646673L,46674L,46675L,46676L,46677L,46678L,46679L,46680L,46681L,46682L,
8449746683L,46684L,46685L,46686L,46687L,46688L,46689L,46690L,46691L,46692L,
8449846693L,46694L,46695L,46696L,46697L,46698L,46699L,46700L,46701L,46702L,
8449946703L,46704L,46705L,46706L,46707L,46708L,46709L,46710L,46711L,46712L,
8450046713L,46714L,46715L,46716L,46717L,46718L,46719L,46720L,46721L,46722L,
8450146723L,46724L,46725L,46726L,46727L,46728L,46729L,46730L,46731L,46732L,
8450246733L,46734L,46735L,46736L,46737L,46738L,46739L,46740L,46741L,46742L,
8450346743L,46744L,46745L,46746L,46747L,46748L,46749L,46750L,46751L,46752L,
8450446753L,46754L,46755L,46756L,46757L,46758L,46759L,46760L,46761L,46762L,
8450546763L,46764L,46765L,46766L,46767L,46768L,46769L,46770L,46771L,46772L,
8450646773L,46774L,46775L,46776L,46777L,46778L,46779L,46780L,46781L,46782L,
8450746783L,46784L,46785L,46786L,46787L,46788L,46789L,46790L,46791L,46792L,
8450846793L,46794L,46795L,46796L,46797L,46798L,46799L,46800L,46801L,46802L,
8450946803L,46804L,46805L,46806L,46807L,46808L,46809L,46810L,46811L,46812L,
8451046813L,46814L,46815L,46816L,46817L,46818L,46819L,46820L,46821L,46822L,
8451146823L,46824L,46825L,46826L,46827L,46828L,46829L,46830L,46831L,46832L,
8451246833L,46834L,46835L,46836L,46837L,46838L,46839L,46840L,46841L,46842L,
8451346843L,46844L,46845L,46846L,46847L,46848L,46849L,46850L,46851L,46852L,
8451446853L,46854L,46855L,46856L,46857L,46858L,46859L,46860L,46861L,46862L,
8451546863L,46864L,46865L,46866L,46867L,46868L,46869L,46870L,46871L,46872L,
8451646873L,46874L,46875L,46876L,46877L,46878L,46879L,46880L,46881L,46882L,
8451746883L,46884L,46885L,46886L,46887L,46888L,46889L,46890L,46891L,46892L,
8451846893L,46894L,46895L,46896L,46897L,46898L,46899L,46900L,46901L,46902L,
8451946903L,46904L,46905L,46906L,46907L,46908L,46909L,46910L,46911L,46912L,
8452046913L,46914L,46915L,46916L,46917L,46918L,46919L,46920L,46921L,46922L,
8452146923L,46924L,46925L,46926L,46927L,46928L,46929L,46930L,46931L,46932L,
8452246933L,46934L,46935L,46936L,46937L,46938L,46939L,46940L,46941L,46942L,
8452346943L,46944L,46945L,46946L,46947L,46948L,46949L,46950L,46951L,46952L,
8452446953L,46954L,46955L,46956L,46957L,46958L,46959L,46960L,46961L,46962L,
8452546963L,46964L,46965L,46966L,46967L,46968L,46969L,46970L,46971L,46972L,
8452646973L,46974L,46975L,46976L,46977L,46978L,46979L,46980L,46981L,46982L,
8452746983L,46984L,46985L,46986L,46987L,46988L,46989L,46990L,46991L,46992L,
8452846993L,46994L,46995L,46996L,46997L,46998L,46999L,47000L,47001L,47002L,
8452947003L,47004L,47005L,47006L,47007L,47008L,47009L,47010L,47011L,47012L,
8453047013L,47014L,47015L,47016L,47017L,47018L,47019L,47020L,47021L,47022L,
8453147023L,47024L,47025L,47026L,47027L,47028L,47029L,47030L,47031L,47032L,
8453247033L,47034L,47035L,47036L,47037L,47038L,47039L,47040L,47041L,47042L,
8453347043L,47044L,47045L,47046L,47047L,47048L,47049L,47050L,47051L,47052L,
8453447053L,47054L,47055L,47056L,47057L,47058L,47059L,47060L,47061L,47062L,
8453547063L,47064L,47065L,47066L,47067L,47068L,47069L,47070L,47071L,47072L,
8453647073L,47074L,47075L,47076L,47077L,47078L,47079L,47080L,47081L,47082L,
8453747083L,47084L,47085L,47086L,47087L,47088L,47089L,47090L,47091L,47092L,
8453847093L,47094L,47095L,47096L,47097L,47098L,47099L,47100L,47101L,47102L,
8453947103L,47104L,47105L,47106L,47107L,47108L,47109L,47110L,47111L,47112L,
8454047113L,47114L,47115L,47116L,47117L,47118L,47119L,47120L,47121L,47122L,
8454147123L,47124L,47125L,47126L,47127L,47128L,47129L,47130L,47131L,47132L,
8454247133L,47134L,47135L,47136L,47137L,47138L,47139L,47140L,47141L,47142L,
8454347143L,47144L,47145L,47146L,47147L,47148L,47149L,47150L,47151L,47152L,
8454447153L,47154L,47155L,47156L,47157L,47158L,47159L,47160L,47161L,47162L,
8454547163L,47164L,47165L,47166L,47167L,47168L,47169L,47170L,47171L,47172L,
8454647173L,47174L,47175L,47176L,47177L,47178L,47179L,47180L,47181L,47182L,
8454747183L,47184L,47185L,47186L,47187L,47188L,47189L,47190L,47191L,47192L,
8454847193L,47194L,47195L,47196L,47197L,47198L,47199L,47200L,47201L,47202L,
8454947203L,47204L,47205L,47206L,47207L,47208L,47209L,47210L,47211L,47212L,
8455047213L,47214L,47215L,47216L,47217L,47218L,47219L,47220L,47221L,47222L,
8455147223L,47224L,47225L,47226L,47227L,47228L,47229L,47230L,47231L,47232L,
8455247233L,47234L,47235L,47236L,47237L,47238L,47239L,47240L,47241L,47242L,
8455347243L,47244L,47245L,47246L,47247L,47248L,47249L,47250L,47251L,47252L,
8455447253L,47254L,47255L,47256L,47257L,47258L,47259L,47260L,47261L,47262L,
8455547263L,47264L,47265L,47266L,47267L,47268L,47269L,47270L,47271L,47272L,
8455647273L,47274L,47275L,47276L,47277L,47278L,47279L,47280L,47281L,47282L,
8455747283L,47284L,47285L,47286L,47287L,47288L,47289L,47290L,47291L,47292L,
8455847293L,47294L,47295L,47296L,47297L,47298L,47299L,47300L,47301L,47302L,
8455947303L,47304L,47305L,47306L,47307L,47308L,47309L,47310L,47311L,47312L,
8456047313L,47314L,47315L,47316L,47317L,47318L,47319L,47320L,47321L,47322L,
8456147323L,47324L,47325L,47326L,47327L,47328L,47329L,47330L,47331L,47332L,
8456247333L,47334L,47335L,47336L,47337L,47338L,47339L,47340L,47341L,47342L,
8456347343L,47344L,47345L,47346L,47347L,47348L,47349L,47350L,47351L,47352L,
8456447353L,47354L,47355L,47356L,47357L,47358L,47359L,47360L,47361L,47362L,
8456547363L,47364L,47365L,47366L,47367L,47368L,47369L,47370L,47371L,47372L,
8456647373L,47374L,47375L,47376L,47377L,47378L,47379L,47380L,47381L,47382L,
8456747383L,47384L,47385L,47386L,47387L,47388L,47389L,47390L,47391L,47392L,
8456847393L,47394L,47395L,47396L,47397L,47398L,47399L,47400L,47401L,47402L,
8456947403L,47404L,47405L,47406L,47407L,47408L,47409L,47410L,47411L,47412L,
8457047413L,47414L,47415L,47416L,47417L,47418L,47419L,47420L,47421L,47422L,
8457147423L,47424L,47425L,47426L,47427L,47428L,47429L,47430L,47431L,47432L,
8457247433L,47434L,47435L,47436L,47437L,47438L,47439L,47440L,47441L,47442L,
8457347443L,47444L,47445L,47446L,47447L,47448L,47449L,47450L,47451L,47452L,
8457447453L,47454L,47455L,47456L,47457L,47458L,47459L,47460L,47461L,47462L,
8457547463L,47464L,47465L,47466L,47467L,47468L,47469L,47470L,47471L,47472L,
8457647473L,47474L,47475L,47476L,47477L,47478L,47479L,47480L,47481L,47482L,
8457747483L,47484L,47485L,47486L,47487L,47488L,47489L,47490L,47491L,47492L,
8457847493L,47494L,47495L,47496L,47497L,47498L,47499L,47500L,47501L,47502L,
8457947503L,47504L,47505L,47506L,47507L,47508L,47509L,47510L,47511L,47512L,
8458047513L,47514L,47515L,47516L,47517L,47518L,47519L,47520L,47521L,47522L,
8458147523L,47524L,47525L,47526L,47527L,47528L,47529L,47530L,47531L,47532L,
8458247533L,47534L,47535L,47536L,47537L,47538L,47539L,47540L,47541L,47542L,
8458347543L,47544L,47545L,47546L,47547L,47548L,47549L,47550L,47551L,47552L,
8458447553L,47554L,47555L,47556L,47557L,47558L,47559L,47560L,47561L,47562L,
8458547563L,47564L,47565L,47566L,47567L,47568L,47569L,47570L,47571L,47572L,
8458647573L,47574L,47575L,47576L,47577L,47578L,47579L,47580L,47581L,47582L,
8458747583L,47584L,47585L,47586L,47587L,47588L,47589L,47590L,47591L,47592L,
8458847593L,47594L,47595L,47596L,47597L,47598L,47599L,47600L,47601L,47602L,
8458947603L,47604L,47605L,47606L,47607L,47608L,47609L,47610L,47611L,47612L,
8459047613L,47614L,47615L,47616L,47617L,47618L,47619L,47620L,47621L,47622L,
8459147623L,47624L,47625L,47626L,47627L,47628L,47629L,47630L,47631L,47632L,
8459247633L,47634L,47635L,47636L,47637L,47638L,47639L,47640L,47641L,47642L,
8459347643L,47644L,47645L,47646L,47647L,47648L,47649L,47650L,47651L,47652L,
8459447653L,47654L,47655L,47656L,47657L,47658L,47659L,47660L,47661L,47662L,
8459547663L,47664L,47665L,47666L,47667L,47668L,47669L,47670L,47671L,47672L,
8459647673L,47674L,47675L,47676L,47677L,47678L,47679L,47680L,47681L,47682L,
8459747683L,47684L,47685L,47686L,47687L,47688L,47689L,47690L,47691L,47692L,
8459847693L,47694L,47695L,47696L,47697L,47698L,47699L,47700L,47701L,47702L,
8459947703L,47704L,47705L,47706L,47707L,47708L,47709L,47710L,47711L,47712L,
8460047713L,47714L,47715L,47716L,47717L,47718L,47719L,47720L,47721L,47722L,
8460147723L,47724L,47725L,47726L,47727L,47728L,47729L,47730L,47731L,47732L,
8460247733L,47734L,47735L,47736L,47737L,47738L,47739L,47740L,47741L,47742L,
8460347743L,47744L,47745L,47746L,47747L,47748L,47749L,47750L,47751L,47752L,
8460447753L,47754L,47755L,47756L,47757L,47758L,47759L,47760L,47761L,47762L,
8460547763L,47764L,47765L,47766L,47767L,47768L,47769L,47770L,47771L,47772L,
8460647773L,47774L,47775L,47776L,47777L,47778L,47779L,47780L,47781L,47782L,
8460747783L,47784L,47785L,47786L,47787L,47788L,47789L,47790L,47791L,47792L,
8460847793L,47794L,47795L,47796L,47797L,47798L,47799L,47800L,47801L,47802L,
8460947803L,47804L,47805L,47806L,47807L,47808L,47809L,47810L,47811L,47812L,
8461047813L,47814L,47815L,47816L,47817L,47818L,47819L,47820L,47821L,47822L,
8461147823L,47824L,47825L,47826L,47827L,47828L,47829L,47830L,47831L,47832L,
8461247833L,47834L,47835L,47836L,47837L,47838L,47839L,47840L,47841L,47842L,
8461347843L,47844L,47845L,47846L,47847L,47848L,47849L,47850L,47851L,47852L,
8461447853L,47854L,47855L,47856L,47857L,47858L,47859L,47860L,47861L,47862L,
8461547863L,47864L,47865L,47866L,47867L,47868L,47869L,47870L,47871L,47872L,
8461647873L,47874L,47875L,47876L,47877L,47878L,47879L,47880L,47881L,47882L,
8461747883L,47884L,47885L,47886L,47887L,47888L,47889L,47890L,47891L,47892L,
8461847893L,47894L,47895L,47896L,47897L,47898L,47899L,47900L,47901L,47902L,
8461947903L,47904L,47905L,47906L,47907L,47908L,47909L,47910L,47911L,47912L,
8462047913L,47914L,47915L,47916L,47917L,47918L,47919L,47920L,47921L,47922L,
8462147923L,47924L,47925L,47926L,47927L,47928L,47929L,47930L,47931L,47932L,
8462247933L,47934L,47935L,47936L,47937L,47938L,47939L,47940L,47941L,47942L,
8462347943L,47944L,47945L,47946L,47947L,47948L,47949L,47950L,47951L,47952L,
8462447953L,47954L,47955L,47956L,47957L,47958L,47959L,47960L,47961L,47962L,
8462547963L,47964L,47965L,47966L,47967L,47968L,47969L,47970L,47971L,47972L,
8462647973L,47974L,47975L,47976L,47977L,47978L,47979L,47980L,47981L,47982L,
8462747983L,47984L,47985L,47986L,47987L,47988L,47989L,47990L,47991L,47992L,
8462847993L,47994L,47995L,47996L,47997L,47998L,47999L,48000L,48001L,48002L,
8462948003L,48004L,48005L,48006L,48007L,48008L,48009L,48010L,48011L,48012L,
8463048013L,48014L,48015L,48016L,48017L,48018L,48019L,48020L,48021L,48022L,
8463148023L,48024L,48025L,48026L,48027L,48028L,48029L,48030L,48031L,48032L,
8463248033L,48034L,48035L,48036L,48037L,48038L,48039L,48040L,48041L,48042L,
8463348043L,48044L,48045L,48046L,48047L,48048L,48049L,48050L,48051L,48052L,
8463448053L,48054L,48055L,48056L,48057L,48058L,48059L,48060L,48061L,48062L,
8463548063L,48064L,48065L,48066L,48067L,48068L,48069L,48070L,48071L,48072L,
8463648073L,48074L,48075L,48076L,48077L,48078L,48079L,48080L,48081L,48082L,
8463748083L,48084L,48085L,48086L,48087L,48088L,48089L,48090L,48091L,48092L,
8463848093L,48094L,48095L,48096L,48097L,48098L,48099L,48100L,48101L,48102L,
8463948103L,48104L,48105L,48106L,48107L,48108L,48109L,48110L,48111L,48112L,
8464048113L,48114L,48115L,48116L,48117L,48118L,48119L,48120L,48121L,48122L,
8464148123L,48124L,48125L,48126L,48127L,48128L,48129L,48130L,48131L,48132L,
8464248133L,48134L,48135L,48136L,48137L,48138L,48139L,48140L,48141L,48142L,
8464348143L,48144L,48145L,48146L,48147L,48148L,48149L,48150L,48151L,48152L,
8464448153L,48154L,48155L,48156L,48157L,48158L,48159L,48160L,48161L,48162L,
8464548163L,48164L,48165L,48166L,48167L,48168L,48169L,48170L,48171L,48172L,
8464648173L,48174L,48175L,48176L,48177L,48178L,48179L,48180L,48181L,48182L,
8464748183L,48184L,48185L,48186L,48187L,48188L,48189L,48190L,48191L,48192L,
8464848193L,48194L,48195L,48196L,48197L,48198L,48199L,48200L,48201L,48202L,
8464948203L,48204L,48205L,48206L,48207L,48208L,48209L,48210L,48211L,48212L,
8465048213L,48214L,48215L,48216L,48217L,48218L,48219L,48220L,48221L,48222L,
8465148223L,48224L,48225L,48226L,48227L,48228L,48229L,48230L,48231L,48232L,
8465248233L,48234L,48235L,48236L,48237L,48238L,48239L,48240L,48241L,48242L,
8465348243L,48244L,48245L,48246L,48247L,48248L,48249L,48250L,48251L,48252L,
8465448253L,48254L,48255L,48256L,48257L,48258L,48259L,48260L,48261L,48262L,
8465548263L,48264L,48265L,48266L,48267L,48268L,48269L,48270L,48271L,48272L,
8465648273L,48274L,48275L,48276L,48277L,48278L,48279L,48280L,48281L,48282L,
8465748283L,48284L,48285L,48286L,48287L,48288L,48289L,48290L,48291L,48292L,
8465848293L,48294L,48295L,48296L,48297L,48298L,48299L,48300L,48301L,48302L,
8465948303L,48304L,48305L,48306L,48307L,48308L,48309L,48310L,48311L,48312L,
8466048313L,48314L,48315L,48316L,48317L,48318L,48319L,48320L,48321L,48322L,
8466148323L,48324L,48325L,48326L,48327L,48328L,48329L,48330L,48331L,48332L,
8466248333L,48334L,48335L,48336L,48337L,48338L,48339L,48340L,48341L,48342L,
8466348343L,48344L,48345L,48346L,48347L,48348L,48349L,48350L,48351L,48352L,
8466448353L,48354L,48355L,48356L,48357L,48358L,48359L,48360L,48361L,48362L,
8466548363L,48364L,48365L,48366L,48367L,48368L,48369L,48370L,48371L,48372L,
8466648373L,48374L,48375L,48376L,48377L,48378L,48379L,48380L,48381L,48382L,
8466748383L,48384L,48385L,48386L,48387L,48388L,48389L,48390L,48391L,48392L,
8466848393L,48394L,48395L,48396L,48397L,48398L,48399L,48400L,48401L,48402L,
8466948403L,48404L,48405L,48406L,48407L,48408L,48409L,48410L,48411L,48412L,
8467048413L,48414L,48415L,48416L,48417L,48418L,48419L,48420L,48421L,48422L,
8467148423L,48424L,48425L,48426L,48427L,48428L,48429L,48430L,48431L,48432L,
8467248433L,48434L,48435L,48436L,48437L,48438L,48439L,48440L,48441L,48442L,
8467348443L,48444L,48445L,48446L,48447L,48448L,48449L,48450L,48451L,48452L,
8467448453L,48454L,48455L,48456L,48457L,48458L,48459L,48460L,48461L,48462L,
8467548463L,48464L,48465L,48466L,48467L,48468L,48469L,48470L,48471L,48472L,
8467648473L,48474L,48475L,48476L,48477L,48478L,48479L,48480L,48481L,48482L,
8467748483L,48484L,48485L,48486L,48487L,48488L,48489L,48490L,48491L,48492L,
8467848493L,48494L,48495L,48496L,48497L,48498L,48499L,48500L,48501L,48502L,
8467948503L,48504L,48505L,48506L,48507L,48508L,48509L,48510L,48511L,48512L,
8468048513L,48514L,48515L,48516L,48517L,48518L,48519L,48520L,48521L,48522L,
8468148523L,48524L,48525L,48526L,48527L,48528L,48529L,48530L,48531L,48532L,
8468248533L,48534L,48535L,48536L,48537L,48538L,48539L,48540L,48541L,48542L,
8468348543L,48544L,48545L,48546L,48547L,48548L,48549L,48550L,48551L,48552L,
8468448553L,48554L,48555L,48556L,48557L,48558L,48559L,48560L,48561L,48562L,
8468548563L,48564L,48565L,48566L,48567L,48568L,48569L,48570L,48571L,48572L,
8468648573L,48574L,48575L,48576L,48577L,48578L,48579L,48580L,48581L,48582L,
8468748583L,48584L,48585L,48586L,48587L,48588L,48589L,48590L,48591L,48592L,
8468848593L,48594L,48595L,48596L,48597L,48598L,48599L,48600L,48601L,48602L,
8468948603L,48604L,48605L,48606L,48607L,48608L,48609L,48610L,48611L,48612L,
8469048613L,48614L,48615L,48616L,48617L,48618L,48619L,48620L,48621L,48622L,
8469148623L,48624L,48625L,48626L,48627L,48628L,48629L,48630L,48631L,48632L,
8469248633L,48634L,48635L,48636L,48637L,48638L,48639L,48640L,48641L,48642L,
8469348643L,48644L,48645L,48646L,48647L,48648L,48649L,48650L,48651L,48652L,
8469448653L,48654L,48655L,48656L,48657L,48658L,48659L,48660L,48661L,48662L,
8469548663L,48664L,48665L,48666L,48667L,48668L,48669L,48670L,48671L,48672L,
8469648673L,48674L,48675L,48676L,48677L,48678L,48679L,48680L,48681L,48682L,
8469748683L,48684L,48685L,48686L,48687L,48688L,48689L,48690L,48691L,48692L,
8469848693L,48694L,48695L,48696L,48697L,48698L,48699L,48700L,48701L,48702L,
8469948703L,48704L,48705L,48706L,48707L,48708L,48709L,48710L,48711L,48712L,
8470048713L,48714L,48715L,48716L,48717L,48718L,48719L,48720L,48721L,48722L,
8470148723L,48724L,48725L,48726L,48727L,48728L,48729L,48730L,48731L,48732L,
8470248733L,48734L,48735L,48736L,48737L,48738L,48739L,48740L,48741L,48742L,
8470348743L,48744L,48745L,48746L,48747L,48748L,48749L,48750L,48751L,48752L,
8470448753L,48754L,48755L,48756L,48757L,48758L,48759L,48760L,48761L,48762L,
8470548763L,48764L,48765L,48766L,48767L,48768L,48769L,48770L,48771L,48772L,
8470648773L,48774L,48775L,48776L,48777L,48778L,48779L,48780L,48781L,48782L,
8470748783L,48784L,48785L,48786L,48787L,48788L,48789L,48790L,48791L,48792L,
8470848793L,48794L,48795L,48796L,48797L,48798L,48799L,48800L,48801L,48802L,
8470948803L,48804L,48805L,48806L,48807L,48808L,48809L,48810L,48811L,48812L,
8471048813L,48814L,48815L,48816L,48817L,48818L,48819L,48820L,48821L,48822L,
8471148823L,48824L,48825L,48826L,48827L,48828L,48829L,48830L,48831L,48832L,
8471248833L,48834L,48835L,48836L,48837L,48838L,48839L,48840L,48841L,48842L,
8471348843L,48844L,48845L,48846L,48847L,48848L,48849L,48850L,48851L,48852L,
8471448853L,48854L,48855L,48856L,48857L,48858L,48859L,48860L,48861L,48862L,
8471548863L,48864L,48865L,48866L,48867L,48868L,48869L,48870L,48871L,48872L,
8471648873L,48874L,48875L,48876L,48877L,48878L,48879L,48880L,48881L,48882L,
8471748883L,48884L,48885L,48886L,48887L,48888L,48889L,48890L,48891L,48892L,
8471848893L,48894L,48895L,48896L,48897L,48898L,48899L,48900L,48901L,48902L,
8471948903L,48904L,48905L,48906L,48907L,48908L,48909L,48910L,48911L,48912L,
8472048913L,48914L,48915L,48916L,48917L,48918L,48919L,48920L,48921L,48922L,
8472148923L,48924L,48925L,48926L,48927L,48928L,48929L,48930L,48931L,48932L,
8472248933L,48934L,48935L,48936L,48937L,48938L,48939L,48940L,48941L,48942L,
8472348943L,48944L,48945L,48946L,48947L,48948L,48949L,48950L,48951L,48952L,
8472448953L,48954L,48955L,48956L,48957L,48958L,48959L,48960L,48961L,48962L,
8472548963L,48964L,48965L,48966L,48967L,48968L,48969L,48970L,48971L,48972L,
8472648973L,48974L,48975L,48976L,48977L,48978L,48979L,48980L,48981L,48982L,
8472748983L,48984L,48985L,48986L,48987L,48988L,48989L,48990L,48991L,48992L,
8472848993L,48994L,48995L,48996L,48997L,48998L,48999L,49000L,49001L,49002L,
8472949003L,49004L,49005L,49006L,49007L,49008L,49009L,49010L,49011L,49012L,
8473049013L,49014L,49015L,49016L,49017L,49018L,49019L,49020L,49021L,49022L,
8473149023L,49024L,49025L,49026L,49027L,49028L,49029L,49030L,49031L,49032L,
8473249033L,49034L,49035L,49036L,49037L,49038L,49039L,49040L,49041L,49042L,
8473349043L,49044L,49045L,49046L,49047L,49048L,49049L,49050L,49051L,49052L,
8473449053L,49054L,49055L,49056L,49057L,49058L,49059L,49060L,49061L,49062L,
8473549063L,49064L,49065L,49066L,49067L,49068L,49069L,49070L,49071L,49072L,
8473649073L,49074L,49075L,49076L,49077L,49078L,49079L,49080L,49081L,49082L,
8473749083L,49084L,49085L,49086L,49087L,49088L,49089L,49090L,49091L,49092L,
8473849093L,49094L,49095L,49096L,49097L,49098L,49099L,49100L,49101L,49102L,
8473949103L,49104L,49105L,49106L,49107L,49108L,49109L,49110L,49111L,49112L,
8474049113L,49114L,49115L,49116L,49117L,49118L,49119L,49120L,49121L,49122L,
8474149123L,49124L,49125L,49126L,49127L,49128L,49129L,49130L,49131L,49132L,
8474249133L,49134L,49135L,49136L,49137L,49138L,49139L,49140L,49141L,49142L,
8474349143L,49144L,49145L,49146L,49147L,49148L,49149L,49150L,49151L,49152L,
8474449153L,49154L,49155L,49156L,49157L,49158L,49159L,49160L,49161L,49162L,
8474549163L,49164L,49165L,49166L,49167L,49168L,49169L,49170L,49171L,49172L,
8474649173L,49174L,49175L,49176L,49177L,49178L,49179L,49180L,49181L,49182L,
8474749183L,49184L,49185L,49186L,49187L,49188L,49189L,49190L,49191L,49192L,
8474849193L,49194L,49195L,49196L,49197L,49198L,49199L,49200L,49201L,49202L,
8474949203L,49204L,49205L,49206L,49207L,49208L,49209L,49210L,49211L,49212L,
8475049213L,49214L,49215L,49216L,49217L,49218L,49219L,49220L,49221L,49222L,
8475149223L,49224L,49225L,49226L,49227L,49228L,49229L,49230L,49231L,49232L,
8475249233L,49234L,49235L,49236L,49237L,49238L,49239L,49240L,49241L,49242L,
8475349243L,49244L,49245L,49246L,49247L,49248L,49249L,49250L,49251L,49252L,
8475449253L,49254L,49255L,49256L,49257L,49258L,49259L,49260L,49261L,49262L,
8475549263L,49264L,49265L,49266L,49267L,49268L,49269L,49270L,49271L,49272L,
8475649273L,49274L,49275L,49276L,49277L,49278L,49279L,49280L,49281L,49282L,
8475749283L,49284L,49285L,49286L,49287L,49288L,49289L,49290L,49291L,49292L,
8475849293L,49294L,49295L,49296L,49297L,49298L,49299L,49300L,49301L,49302L,
8475949303L,49304L,49305L,49306L,49307L,49308L,49309L,49310L,49311L,49312L,
8476049313L,49314L,49315L,49316L,49317L,49318L,49319L,49320L,49321L,49322L,
8476149323L,49324L,49325L,49326L,49327L,49328L,49329L,49330L,49331L,49332L,
8476249333L,49334L,49335L,49336L,49337L,49338L,49339L,49340L,49341L,49342L,
8476349343L,49344L,49345L,49346L,49347L,49348L,49349L,49350L,49351L,49352L,
8476449353L,49354L,49355L,49356L,49357L,49358L,49359L,49360L,49361L,49362L,
8476549363L,49364L,49365L,49366L,49367L,49368L,49369L,49370L,49371L,49372L,
8476649373L,49374L,49375L,49376L,49377L,49378L,49379L,49380L,49381L,49382L,
8476749383L,49384L,49385L,49386L,49387L,49388L,49389L,49390L,49391L,49392L,
8476849393L,49394L,49395L,49396L,49397L,49398L,49399L,49400L,49401L,49402L,
8476949403L,49404L,49405L,49406L,49407L,49408L,49409L,49410L,49411L,49412L,
8477049413L,49414L,49415L,49416L,49417L,49418L,49419L,49420L,49421L,49422L,
8477149423L,49424L,49425L,49426L,49427L,49428L,49429L,49430L,49431L,49432L,
8477249433L,49434L,49435L,49436L,49437L,49438L,49439L,49440L,49441L,49442L,
8477349443L,49444L,49445L,49446L,49447L,49448L,49449L,49450L,49451L,49452L,
8477449453L,49454L,49455L,49456L,49457L,49458L,49459L,49460L,49461L,49462L,
8477549463L,49464L,49465L,49466L,49467L,49468L,49469L,49470L,49471L,49472L,
8477649473L,49474L,49475L,49476L,49477L,49478L,49479L,49480L,49481L,49482L,
8477749483L,49484L,49485L,49486L,49487L,49488L,49489L,49490L,49491L,49492L,
8477849493L,49494L,49495L,49496L,49497L,49498L,49499L,49500L,49501L,49502L,
8477949503L,49504L,49505L,49506L,49507L,49508L,49509L,49510L,49511L,49512L,
8478049513L,49514L,49515L,49516L,49517L,49518L,49519L,49520L,49521L,49522L,
8478149523L,49524L,49525L,49526L,49527L,49528L,49529L,49530L,49531L,49532L,
8478249533L,49534L,49535L,49536L,49537L,49538L,49539L,49540L,49541L,49542L,
8478349543L,49544L,49545L,49546L,49547L,49548L,49549L,49550L,49551L,49552L,
8478449553L,49554L,49555L,49556L,49557L,49558L,49559L,49560L,49561L,49562L,
8478549563L,49564L,49565L,49566L,49567L,49568L,49569L,49570L,49571L,49572L,
8478649573L,49574L,49575L,49576L,49577L,49578L,49579L,49580L,49581L,49582L,
8478749583L,49584L,49585L,49586L,49587L,49588L,49589L,49590L,49591L,49592L,
8478849593L,49594L,49595L,49596L,49597L,49598L,49599L,49600L,49601L,49602L,
8478949603L,49604L,49605L,49606L,49607L,49608L,49609L,49610L,49611L,49612L,
8479049613L,49614L,49615L,49616L,49617L,49618L,49619L,49620L,49621L,49622L,
8479149623L,49624L,49625L,49626L,49627L,49628L,49629L,49630L,49631L,49632L,
8479249633L,49634L,49635L,49636L,49637L,49638L,49639L,49640L,49641L,49642L,
8479349643L,49644L,49645L,49646L,49647L,49648L,49649L,49650L,49651L,49652L,
8479449653L,49654L,49655L,49656L,49657L,49658L,49659L,49660L,49661L,49662L,
8479549663L,49664L,49665L,49666L,49667L,49668L,49669L,49670L,49671L,49672L,
8479649673L,49674L,49675L,49676L,49677L,49678L,49679L,49680L,49681L,49682L,
8479749683L,49684L,49685L,49686L,49687L,49688L,49689L,49690L,49691L,49692L,
8479849693L,49694L,49695L,49696L,49697L,49698L,49699L,49700L,49701L,49702L,
8479949703L,49704L,49705L,49706L,49707L,49708L,49709L,49710L,49711L,49712L,
8480049713L,49714L,49715L,49716L,49717L,49718L,49719L,49720L,49721L,49722L,
8480149723L,49724L,49725L,49726L,49727L,49728L,49729L,49730L,49731L,49732L,
8480249733L,49734L,49735L,49736L,49737L,49738L,49739L,49740L,49741L,49742L,
8480349743L,49744L,49745L,49746L,49747L,49748L,49749L,49750L,49751L,49752L,
8480449753L,49754L,49755L,49756L,49757L,49758L,49759L,49760L,49761L,49762L,
8480549763L,49764L,49765L,49766L,49767L,49768L,49769L,49770L,49771L,49772L,
8480649773L,49774L,49775L,49776L,49777L,49778L,49779L,49780L,49781L,49782L,
8480749783L,49784L,49785L,49786L,49787L,49788L,49789L,49790L,49791L,49792L,
8480849793L,49794L,49795L,49796L,49797L,49798L,49799L,49800L,49801L,49802L,
8480949803L,49804L,49805L,49806L,49807L,49808L,49809L,49810L,49811L,49812L,
8481049813L,49814L,49815L,49816L,49817L,49818L,49819L,49820L,49821L,49822L,
8481149823L,49824L,49825L,49826L,49827L,49828L,49829L,49830L,49831L,49832L,
8481249833L,49834L,49835L,49836L,49837L,49838L,49839L,49840L,49841L,49842L,
8481349843L,49844L,49845L,49846L,49847L,49848L,49849L,49850L,49851L,49852L,
8481449853L,49854L,49855L,49856L,49857L,49858L,49859L,49860L,49861L,49862L,
8481549863L,49864L,49865L,49866L,49867L,49868L,49869L,49870L,49871L,49872L,
8481649873L,49874L,49875L,49876L,49877L,49878L,49879L,49880L,49881L,49882L,
8481749883L,49884L,49885L,49886L,49887L,49888L,49889L,49890L,49891L,49892L,
8481849893L,49894L,49895L,49896L,49897L,49898L,49899L,49900L,49901L,49902L,
8481949903L,49904L,49905L,49906L,49907L,49908L,49909L,49910L,49911L,49912L,
8482049913L,49914L,49915L,49916L,49917L,49918L,49919L,49920L,49921L,49922L,
8482149923L,49924L,49925L,49926L,49927L,49928L,49929L,49930L,49931L,49932L,
8482249933L,49934L,49935L,49936L,49937L,49938L,49939L,49940L,49941L,49942L,
8482349943L,49944L,49945L,49946L,49947L,49948L,49949L,49950L,49951L,49952L,
8482449953L,49954L,49955L,49956L,49957L,49958L,49959L,49960L,49961L,49962L,
8482549963L,49964L,49965L,49966L,49967L,49968L,49969L,49970L,49971L,49972L,
8482649973L,49974L,49975L,49976L,49977L,49978L,49979L,49980L,49981L,49982L,
8482749983L,49984L,49985L,49986L,49987L,49988L,49989L,49990L,49991L,49992L,
8482849993L,49994L,49995L,49996L,49997L,49998L,49999L,50000L,50001L,50002L,
8482950003L,50004L,50005L,50006L,50007L,50008L,50009L,50010L,50011L,50012L,
8483050013L,50014L,50015L,50016L,50017L,50018L,50019L,50020L,50021L,50022L,
8483150023L,50024L,50025L,50026L,50027L,50028L,50029L,50030L,50031L,50032L,
8483250033L,50034L,50035L,50036L,50037L,50038L,50039L,50040L,50041L,50042L,
8483350043L,50044L,50045L,50046L,50047L,50048L,50049L,50050L,50051L,50052L,
8483450053L,50054L,50055L,50056L,50057L,50058L,50059L,50060L,50061L,50062L,
8483550063L,50064L,50065L,50066L,50067L,50068L,50069L,50070L,50071L,50072L,
8483650073L,50074L,50075L,50076L,50077L,50078L,50079L,50080L,50081L,50082L,
8483750083L,50084L,50085L,50086L,50087L,50088L,50089L,50090L,50091L,50092L,
8483850093L,50094L,50095L,50096L,50097L,50098L,50099L,50100L,50101L,50102L,
8483950103L,50104L,50105L,50106L,50107L,50108L,50109L,50110L,50111L,50112L,
8484050113L,50114L,50115L,50116L,50117L,50118L,50119L,50120L,50121L,50122L,
8484150123L,50124L,50125L,50126L,50127L,50128L,50129L,50130L,50131L,50132L,
8484250133L,50134L,50135L,50136L,50137L,50138L,50139L,50140L,50141L,50142L,
8484350143L,50144L,50145L,50146L,50147L,50148L,50149L,50150L,50151L,50152L,
8484450153L,50154L,50155L,50156L,50157L,50158L,50159L,50160L,50161L,50162L,
8484550163L,50164L,50165L,50166L,50167L,50168L,50169L,50170L,50171L,50172L,
8484650173L,50174L,50175L,50176L,50177L,50178L,50179L,50180L,50181L,50182L,
8484750183L,50184L,50185L,50186L,50187L,50188L,50189L,50190L,50191L,50192L,
8484850193L,50194L,50195L,50196L,50197L,50198L,50199L,50200L,50201L,50202L,
8484950203L,50204L,50205L,50206L,50207L,50208L,50209L,50210L,50211L,50212L,
8485050213L,50214L,50215L,50216L,50217L,50218L,50219L,50220L,50221L,50222L,
8485150223L,50224L,50225L,50226L,50227L,50228L,50229L,50230L,50231L,50232L,
8485250233L,50234L,50235L,50236L,50237L,50238L,50239L,50240L,50241L,50242L,
8485350243L,50244L,50245L,50246L,50247L,50248L,50249L,50250L,50251L,50252L,
8485450253L,50254L,50255L,50256L,50257L,50258L,50259L,50260L,50261L,50262L,
8485550263L,50264L,50265L,50266L,50267L,50268L,50269L,50270L,50271L,50272L,
8485650273L,50274L,50275L,50276L,50277L,50278L,50279L,50280L,50281L,50282L,
8485750283L,50284L,50285L,50286L,50287L,50288L,50289L,50290L,50291L,50292L,
8485850293L,50294L,50295L,50296L,50297L,50298L,50299L,50300L,50301L,50302L,
8485950303L,50304L,50305L,50306L,50307L,50308L,50309L,50310L,50311L,50312L,
8486050313L,50314L,50315L,50316L,50317L,50318L,50319L,50320L,50321L,50322L,
8486150323L,50324L,50325L,50326L,50327L,50328L,50329L,50330L,50331L,50332L,
8486250333L,50334L,50335L,50336L,50337L,50338L,50339L,50340L,50341L,50342L,
8486350343L,50344L,50345L,50346L,50347L,50348L,50349L,50350L,50351L,50352L,
8486450353L,50354L,50355L,50356L,50357L,50358L,50359L,50360L,50361L,50362L,
8486550363L,50364L,50365L,50366L,50367L,50368L,50369L,50370L,50371L,50372L,
8486650373L,50374L,50375L,50376L,50377L,50378L,50379L,50380L,50381L,50382L,
8486750383L,50384L,50385L,50386L,50387L,50388L,50389L,50390L,50391L,50392L,
8486850393L,50394L,50395L,50396L,50397L,50398L,50399L,50400L,50401L,50402L,
8486950403L,50404L,50405L,50406L,50407L,50408L,50409L,50410L,50411L,50412L,
8487050413L,50414L,50415L,50416L,50417L,50418L,50419L,50420L,50421L,50422L,
8487150423L,50424L,50425L,50426L,50427L,50428L,50429L,50430L,50431L,50432L,
8487250433L,50434L,50435L,50436L,50437L,50438L,50439L,50440L,50441L,50442L,
8487350443L,50444L,50445L,50446L,50447L,50448L,50449L,50450L,50451L,50452L,
8487450453L,50454L,50455L,50456L,50457L,50458L,50459L,50460L,50461L,50462L,
8487550463L,50464L,50465L,50466L,50467L,50468L,50469L,50470L,50471L,50472L,
8487650473L,50474L,50475L,50476L,50477L,50478L,50479L,50480L,50481L,50482L,
8487750483L,50484L,50485L,50486L,50487L,50488L,50489L,50490L,50491L,50492L,
8487850493L,50494L,50495L,50496L,50497L,50498L,50499L,50500L,50501L,50502L,
8487950503L,50504L,50505L,50506L,50507L,50508L,50509L,50510L,50511L,50512L,
8488050513L,50514L,50515L,50516L,50517L,50518L,50519L,50520L,50521L,50522L,
8488150523L,50524L,50525L,50526L,50527L,50528L,50529L,50530L,50531L,50532L,
8488250533L,50534L,50535L,50536L,50537L,50538L,50539L,50540L,50541L,50542L,
8488350543L,50544L,50545L,50546L,50547L,50548L,50549L,50550L,50551L,50552L,
8488450553L,50554L,50555L,50556L,50557L,50558L,50559L,50560L,50561L,50562L,
8488550563L,50564L,50565L,50566L,50567L,50568L,50569L,50570L,50571L,50572L,
8488650573L,50574L,50575L,50576L,50577L,50578L,50579L,50580L,50581L,50582L,
8488750583L,50584L,50585L,50586L,50587L,50588L,50589L,50590L,50591L,50592L,
8488850593L,50594L,50595L,50596L,50597L,50598L,50599L,50600L,50601L,50602L,
8488950603L,50604L,50605L,50606L,50607L,50608L,50609L,50610L,50611L,50612L,
8489050613L,50614L,50615L,50616L,50617L,50618L,50619L,50620L,50621L,50622L,
8489150623L,50624L,50625L,50626L,50627L,50628L,50629L,50630L,50631L,50632L,
8489250633L,50634L,50635L,50636L,50637L,50638L,50639L,50640L,50641L,50642L,
8489350643L,50644L,50645L,50646L,50647L,50648L,50649L,50650L,50651L,50652L,
8489450653L,50654L,50655L,50656L,50657L,50658L,50659L,50660L,50661L,50662L,
8489550663L,50664L,50665L,50666L,50667L,50668L,50669L,50670L,50671L,50672L,
8489650673L,50674L,50675L,50676L,50677L,50678L,50679L,50680L,50681L,50682L,
8489750683L,50684L,50685L,50686L,50687L,50688L,50689L,50690L,50691L,50692L,
8489850693L,50694L,50695L,50696L,50697L,50698L,50699L,50700L,50701L,50702L,
8489950703L,50704L,50705L,50706L,50707L,50708L,50709L,50710L,50711L,50712L,
8490050713L,50714L,50715L,50716L,50717L,50718L,50719L,50720L,50721L,50722L,
8490150723L,50724L,50725L,50726L,50727L,50728L,50729L,50730L,50731L,50732L,
8490250733L,50734L,50735L,50736L,50737L,50738L,50739L,50740L,50741L,50742L,
8490350743L,50744L,50745L,50746L,50747L,50748L,50749L,50750L,50751L,50752L,
8490450753L,50754L,50755L,50756L,50757L,50758L,50759L,50760L,50761L,50762L,
8490550763L,50764L,50765L,50766L,50767L,50768L,50769L,50770L,50771L,50772L,
8490650773L,50774L,50775L,50776L,50777L,50778L,50779L,50780L,50781L,50782L,
8490750783L,50784L,50785L,50786L,50787L,50788L,50789L,50790L,50791L,50792L,
8490850793L,50794L,50795L,50796L,50797L,50798L,50799L,50800L,50801L,50802L,
8490950803L,50804L,50805L,50806L,50807L,50808L,50809L,50810L,50811L,50812L,
8491050813L,50814L,50815L,50816L,50817L,50818L,50819L,50820L,50821L,50822L,
8491150823L,50824L,50825L,50826L,50827L,50828L,50829L,50830L,50831L,50832L,
8491250833L,50834L,50835L,50836L,50837L,50838L,50839L,50840L,50841L,50842L,
8491350843L,50844L,50845L,50846L,50847L,50848L,50849L,50850L,50851L,50852L,
8491450853L,50854L,50855L,50856L,50857L,50858L,50859L,50860L,50861L,50862L,
8491550863L,50864L,50865L,50866L,50867L,50868L,50869L,50870L,50871L,50872L,
8491650873L,50874L,50875L,50876L,50877L,50878L,50879L,50880L,50881L,50882L,
8491750883L,50884L,50885L,50886L,50887L,50888L,50889L,50890L,50891L,50892L,
8491850893L,50894L,50895L,50896L,50897L,50898L,50899L,50900L,50901L,50902L,
8491950903L,50904L,50905L,50906L,50907L,50908L,50909L,50910L,50911L,50912L,
8492050913L,50914L,50915L,50916L,50917L,50918L,50919L,50920L,50921L,50922L,
8492150923L,50924L,50925L,50926L,50927L,50928L,50929L,50930L,50931L,50932L,
8492250933L,50934L,50935L,50936L,50937L,50938L,50939L,50940L,50941L,50942L,
8492350943L,50944L,50945L,50946L,50947L,50948L,50949L,50950L,50951L,50952L,
8492450953L,50954L,50955L,50956L,50957L,50958L,50959L,50960L,50961L,50962L,
8492550963L,50964L,50965L,50966L,50967L,50968L,50969L,50970L,50971L,50972L,
8492650973L,50974L,50975L,50976L,50977L,50978L,50979L,50980L,50981L,50982L,
8492750983L,50984L,50985L,50986L,50987L,50988L,50989L,50990L,50991L,50992L,
8492850993L,50994L,50995L,50996L,50997L,50998L,50999L,51000L,51001L,51002L,
8492951003L,51004L,51005L,51006L,51007L,51008L,51009L,51010L,51011L,51012L,
8493051013L,51014L,51015L,51016L,51017L,51018L,51019L,51020L,51021L,51022L,
8493151023L,51024L,51025L,51026L,51027L,51028L,51029L,51030L,51031L,51032L,
8493251033L,51034L,51035L,51036L,51037L,51038L,51039L,51040L,51041L,51042L,
8493351043L,51044L,51045L,51046L,51047L,51048L,51049L,51050L,51051L,51052L,
8493451053L,51054L,51055L,51056L,51057L,51058L,51059L,51060L,51061L,51062L,
8493551063L,51064L,51065L,51066L,51067L,51068L,51069L,51070L,51071L,51072L,
8493651073L,51074L,51075L,51076L,51077L,51078L,51079L,51080L,51081L,51082L,
8493751083L,51084L,51085L,51086L,51087L,51088L,51089L,51090L,51091L,51092L,
8493851093L,51094L,51095L,51096L,51097L,51098L,51099L,51100L,51101L,51102L,
8493951103L,51104L,51105L,51106L,51107L,51108L,51109L,51110L,51111L,51112L,
8494051113L,51114L,51115L,51116L,51117L,51118L,51119L,51120L,51121L,51122L,
8494151123L,51124L,51125L,51126L,51127L,51128L,51129L,51130L,51131L,51132L,
8494251133L,51134L,51135L,51136L,51137L,51138L,51139L,51140L,51141L,51142L,
8494351143L,51144L,51145L,51146L,51147L,51148L,51149L,51150L,51151L,51152L,
8494451153L,51154L,51155L,51156L,51157L,51158L,51159L,51160L,51161L,51162L,
8494551163L,51164L,51165L,51166L,51167L,51168L,51169L,51170L,51171L,51172L,
8494651173L,51174L,51175L,51176L,51177L,51178L,51179L,51180L,51181L,51182L,
8494751183L,51184L,51185L,51186L,51187L,51188L,51189L,51190L,51191L,51192L,
8494851193L,51194L,51195L,51196L,51197L,51198L,51199L,51200L,51201L,51202L,
8494951203L,51204L,51205L,51206L,51207L,51208L,51209L,51210L,51211L,51212L,
8495051213L,51214L,51215L,51216L,51217L,51218L,51219L,51220L,51221L,51222L,
8495151223L,51224L,51225L,51226L,51227L,51228L,51229L,51230L,51231L,51232L,
8495251233L,51234L,51235L,51236L,51237L,51238L,51239L,51240L,51241L,51242L,
8495351243L,51244L,51245L,51246L,51247L,51248L,51249L,51250L,51251L,51252L,
8495451253L,51254L,51255L,51256L,51257L,51258L,51259L,51260L,51261L,51262L,
8495551263L,51264L,51265L,51266L,51267L,51268L,51269L,51270L,51271L,51272L,
8495651273L,51274L,51275L,51276L,51277L,51278L,51279L,51280L,51281L,51282L,
8495751283L,51284L,51285L,51286L,51287L,51288L,51289L,51290L,51291L,51292L,
8495851293L,51294L,51295L,51296L,51297L,51298L,51299L,51300L,51301L,51302L,
8495951303L,51304L,51305L,51306L,51307L,51308L,51309L,51310L,51311L,51312L,
8496051313L,51314L,51315L,51316L,51317L,51318L,51319L,51320L,51321L,51322L,
8496151323L,51324L,51325L,51326L,51327L,51328L,51329L,51330L,51331L,51332L,
8496251333L,51334L,51335L,51336L,51337L,51338L,51339L,51340L,51341L,51342L,
8496351343L,51344L,51345L,51346L,51347L,51348L,51349L,51350L,51351L,51352L,
8496451353L,51354L,51355L,51356L,51357L,51358L,51359L,51360L,51361L,51362L,
8496551363L,51364L,51365L,51366L,51367L,51368L,51369L,51370L,51371L,51372L,
8496651373L,51374L,51375L,51376L,51377L,51378L,51379L,51380L,51381L,51382L,
8496751383L,51384L,51385L,51386L,51387L,51388L,51389L,51390L,51391L,51392L,
8496851393L,51394L,51395L,51396L,51397L,51398L,51399L,51400L,51401L,51402L,
8496951403L,51404L,51405L,51406L,51407L,51408L,51409L,51410L,51411L,51412L,
8497051413L,51414L,51415L,51416L,51417L,51418L,51419L,51420L,51421L,51422L,
8497151423L,51424L,51425L,51426L,51427L,51428L,51429L,51430L,51431L,51432L,
8497251433L,51434L,51435L,51436L,51437L,51438L,51439L,51440L,51441L,51442L,
8497351443L,51444L,51445L,51446L,51447L,51448L,51449L,51450L,51451L,51452L,
8497451453L,51454L,51455L,51456L,51457L,51458L,51459L,51460L,51461L,51462L,
8497551463L,51464L,51465L,51466L,51467L,51468L,51469L,51470L,51471L,51472L,
8497651473L,51474L,51475L,51476L,51477L,51478L,51479L,51480L,51481L,51482L,
8497751483L,51484L,51485L,51486L,51487L,51488L,51489L,51490L,51491L,51492L,
8497851493L,51494L,51495L,51496L,51497L,51498L,51499L,51500L,51501L,51502L,
8497951503L,51504L,51505L,51506L,51507L,51508L,51509L,51510L,51511L,51512L,
8498051513L,51514L,51515L,51516L,51517L,51518L,51519L,51520L,51521L,51522L,
8498151523L,51524L,51525L,51526L,51527L,51528L,51529L,51530L,51531L,51532L,
8498251533L,51534L,51535L,51536L,51537L,51538L,51539L,51540L,51541L,51542L,
8498351543L,51544L,51545L,51546L,51547L,51548L,51549L,51550L,51551L,51552L,
8498451553L,51554L,51555L,51556L,51557L,51558L,51559L,51560L,51561L,51562L,
8498551563L,51564L,51565L,51566L,51567L,51568L,51569L,51570L,51571L,51572L,
8498651573L,51574L,51575L,51576L,51577L,51578L,51579L,51580L,51581L,51582L,
8498751583L,51584L,51585L,51586L,51587L,51588L,51589L,51590L,51591L,51592L,
8498851593L,51594L,51595L,51596L,51597L,51598L,51599L,51600L,51601L,51602L,
8498951603L,51604L,51605L,51606L,51607L,51608L,51609L,51610L,51611L,51612L,
8499051613L,51614L,51615L,51616L,51617L,51618L,51619L,51620L,51621L,51622L,
8499151623L,51624L,51625L,51626L,51627L,51628L,51629L,51630L,51631L,51632L,
8499251633L,51634L,51635L,51636L,51637L,51638L,51639L,51640L,51641L,51642L,
8499351643L,51644L,51645L,51646L,51647L,51648L,51649L,51650L,51651L,51652L,
8499451653L,51654L,51655L,51656L,51657L,51658L,51659L,51660L,51661L,51662L,
8499551663L,51664L,51665L,51666L,51667L,51668L,51669L,51670L,51671L,51672L,
8499651673L,51674L,51675L,51676L,51677L,51678L,51679L,51680L,51681L,51682L,
8499751683L,51684L,51685L,51686L,51687L,51688L,51689L,51690L,51691L,51692L,
8499851693L,51694L,51695L,51696L,51697L,51698L,51699L,51700L,51701L,51702L,
8499951703L,51704L,51705L,51706L,51707L,51708L,51709L,51710L,51711L,51712L,
8500051713L,51714L,51715L,51716L,51717L,51718L,51719L,51720L,51721L,51722L,
8500151723L,51724L,51725L,51726L,51727L,51728L,51729L,51730L,51731L,51732L,
8500251733L,51734L,51735L,51736L,51737L,51738L,51739L,51740L,51741L,51742L,
8500351743L,51744L,51745L,51746L,51747L,51748L,51749L,51750L,51751L,51752L,
8500451753L,51754L,51755L,51756L,51757L,51758L,51759L,51760L,51761L,51762L,
8500551763L,51764L,51765L,51766L,51767L,51768L,51769L,51770L,51771L,51772L,
8500651773L,51774L,51775L,51776L,51777L,51778L,51779L,51780L,51781L,51782L,
8500751783L,51784L,51785L,51786L,51787L,51788L,51789L,51790L,51791L,51792L,
8500851793L,51794L,51795L,51796L,51797L,51798L,51799L,51800L,51801L,51802L,
8500951803L,51804L,51805L,51806L,51807L,51808L,51809L,51810L,51811L,51812L,
8501051813L,51814L,51815L,51816L,51817L,51818L,51819L,51820L,51821L,51822L,
8501151823L,51824L,51825L,51826L,51827L,51828L,51829L,51830L,51831L,51832L,
8501251833L,51834L,51835L,51836L,51837L,51838L,51839L,51840L,51841L,51842L,
8501351843L,51844L,51845L,51846L,51847L,51848L,51849L,51850L,51851L,51852L,
8501451853L,51854L,51855L,51856L,51857L,51858L,51859L,51860L,51861L,51862L,
8501551863L,51864L,51865L,51866L,51867L,51868L,51869L,51870L,51871L,51872L,
8501651873L,51874L,51875L,51876L,51877L,51878L,51879L,51880L,51881L,51882L,
8501751883L,51884L,51885L,51886L,51887L,51888L,51889L,51890L,51891L,51892L,
8501851893L,51894L,51895L,51896L,51897L,51898L,51899L,51900L,51901L,51902L,
8501951903L,51904L,51905L,51906L,51907L,51908L,51909L,51910L,51911L,51912L,
8502051913L,51914L,51915L,51916L,51917L,51918L,51919L,51920L,51921L,51922L,
8502151923L,51924L,51925L,51926L,51927L,51928L,51929L,51930L,51931L,51932L,
8502251933L,51934L,51935L,51936L,51937L,51938L,51939L,51940L,51941L,51942L,
8502351943L,51944L,51945L,51946L,51947L,51948L,51949L,51950L,51951L,51952L,
8502451953L,51954L,51955L,51956L,51957L,51958L,51959L,51960L,51961L,51962L,
8502551963L,51964L,51965L,51966L,51967L,51968L,51969L,51970L,51971L,51972L,
8502651973L,51974L,51975L,51976L,51977L,51978L,51979L,51980L,51981L,51982L,
8502751983L,51984L,51985L,51986L,51987L,51988L,51989L,51990L,51991L,51992L,
8502851993L,51994L,51995L,51996L,51997L,51998L,51999L,52000L,52001L,52002L,
8502952003L,52004L,52005L,52006L,52007L,52008L,52009L,52010L,52011L,52012L,
8503052013L,52014L,52015L,52016L,52017L,52018L,52019L,52020L,52021L,52022L,
8503152023L,52024L,52025L,52026L,52027L,52028L,52029L,52030L,52031L,52032L,
8503252033L,52034L,52035L,52036L,52037L,52038L,52039L,52040L,52041L,52042L,
8503352043L,52044L,52045L,52046L,52047L,52048L,52049L,52050L,52051L,52052L,
8503452053L,52054L,52055L,52056L,52057L,52058L,52059L,52060L,52061L,52062L,
8503552063L,52064L,52065L,52066L,52067L,52068L,52069L,52070L,52071L,52072L,
8503652073L,52074L,52075L,52076L,52077L,52078L,52079L,52080L,52081L,52082L,
8503752083L,52084L,52085L,52086L,52087L,52088L,52089L,52090L,52091L,52092L,
8503852093L,52094L,52095L,52096L,52097L,52098L,52099L,52100L,52101L,52102L,
8503952103L,52104L,52105L,52106L,52107L,52108L,52109L,52110L,52111L,52112L,
8504052113L,52114L,52115L,52116L,52117L,52118L,52119L,52120L,52121L,52122L,
8504152123L,52124L,52125L,52126L,52127L,52128L,52129L,52130L,52131L,52132L,
8504252133L,52134L,52135L,52136L,52137L,52138L,52139L,52140L,52141L,52142L,
8504352143L,52144L,52145L,52146L,52147L,52148L,52149L,52150L,52151L,52152L,
8504452153L,52154L,52155L,52156L,52157L,52158L,52159L,52160L,52161L,52162L,
8504552163L,52164L,52165L,52166L,52167L,52168L,52169L,52170L,52171L,52172L,
8504652173L,52174L,52175L,52176L,52177L,52178L,52179L,52180L,52181L,52182L,
8504752183L,52184L,52185L,52186L,52187L,52188L,52189L,52190L,52191L,52192L,
8504852193L,52194L,52195L,52196L,52197L,52198L,52199L,52200L,52201L,52202L,
8504952203L,52204L,52205L,52206L,52207L,52208L,52209L,52210L,52211L,52212L,
8505052213L,52214L,52215L,52216L,52217L,52218L,52219L,52220L,52221L,52222L,
8505152223L,52224L,52225L,52226L,52227L,52228L,52229L,52230L,52231L,52232L,
8505252233L,52234L,52235L,52236L,52237L,52238L,52239L,52240L,52241L,52242L,
8505352243L,52244L,52245L,52246L,52247L,52248L,52249L,52250L,52251L,52252L,
8505452253L,52254L,52255L,52256L,52257L,52258L,52259L,52260L,52261L,52262L,
8505552263L,52264L,52265L,52266L,52267L,52268L,52269L,52270L,52271L,52272L,
8505652273L,52274L,52275L,52276L,52277L,52278L,52279L,52280L,52281L,52282L,
8505752283L,52284L,52285L,52286L,52287L,52288L,52289L,52290L,52291L,52292L,
8505852293L,52294L,52295L,52296L,52297L,52298L,52299L,52300L,52301L,52302L,
8505952303L,52304L,52305L,52306L,52307L,52308L,52309L,52310L,52311L,52312L,
8506052313L,52314L,52315L,52316L,52317L,52318L,52319L,52320L,52321L,52322L,
8506152323L,52324L,52325L,52326L,52327L,52328L,52329L,52330L,52331L,52332L,
8506252333L,52334L,52335L,52336L,52337L,52338L,52339L,52340L,52341L,52342L,
8506352343L,52344L,52345L,52346L,52347L,52348L,52349L,52350L,52351L,52352L,
8506452353L,52354L,52355L,52356L,52357L,52358L,52359L,52360L,52361L,52362L,
8506552363L,52364L,52365L,52366L,52367L,52368L,52369L,52370L,52371L,52372L,
8506652373L,52374L,52375L,52376L,52377L,52378L,52379L,52380L,52381L,52382L,
8506752383L,52384L,52385L,52386L,52387L,52388L,52389L,52390L,52391L,52392L,
8506852393L,52394L,52395L,52396L,52397L,52398L,52399L,52400L,52401L,52402L,
8506952403L,52404L,52405L,52406L,52407L,52408L,52409L,52410L,52411L,52412L,
8507052413L,52414L,52415L,52416L,52417L,52418L,52419L,52420L,52421L,52422L,
8507152423L,52424L,52425L,52426L,52427L,52428L,52429L,52430L,52431L,52432L,
8507252433L,52434L,52435L,52436L,52437L,52438L,52439L,52440L,52441L,52442L,
8507352443L,52444L,52445L,52446L,52447L,52448L,52449L,52450L,52451L,52452L,
8507452453L,52454L,52455L,52456L,52457L,52458L,52459L,52460L,52461L,52462L,
8507552463L,52464L,52465L,52466L,52467L,52468L,52469L,52470L,52471L,52472L,
8507652473L,52474L,52475L,52476L,52477L,52478L,52479L,52480L,52481L,52482L,
8507752483L,52484L,52485L,52486L,52487L,52488L,52489L,52490L,52491L,52492L,
8507852493L,52494L,52495L,52496L,52497L,52498L,52499L,52500L,52501L,52502L,
8507952503L,52504L,52505L,52506L,52507L,52508L,52509L,52510L,52511L,52512L,
8508052513L,52514L,52515L,52516L,52517L,52518L,52519L,52520L,52521L,52522L,
8508152523L,52524L,52525L,52526L,52527L,52528L,52529L,52530L,52531L,52532L,
8508252533L,52534L,52535L,52536L,52537L,52538L,52539L,52540L,52541L,52542L,
8508352543L,52544L,52545L,52546L,52547L,52548L,52549L,52550L,52551L,52552L,
8508452553L,52554L,52555L,52556L,52557L,52558L,52559L,52560L,52561L,52562L,
8508552563L,52564L,52565L,52566L,52567L,52568L,52569L,52570L,52571L,52572L,
8508652573L,52574L,52575L,52576L,52577L,52578L,52579L,52580L,52581L,52582L,
8508752583L,52584L,52585L,52586L,52587L,52588L,52589L,52590L,52591L,52592L,
8508852593L,52594L,52595L,52596L,52597L,52598L,52599L,52600L,52601L,52602L,
8508952603L,52604L,52605L,52606L,52607L,52608L,52609L,52610L,52611L,52612L,
8509052613L,52614L,52615L,52616L,52617L,52618L,52619L,52620L,52621L,52622L,
8509152623L,52624L,52625L,52626L,52627L,52628L,52629L,52630L,52631L,52632L,
8509252633L,52634L,52635L,52636L,52637L,52638L,52639L,52640L,52641L,52642L,
8509352643L,52644L,52645L,52646L,52647L,52648L,52649L,52650L,52651L,52652L,
8509452653L,52654L,52655L,52656L,52657L,52658L,52659L,52660L,52661L,52662L,
8509552663L,52664L,52665L,52666L,52667L,52668L,52669L,52670L,52671L,52672L,
8509652673L,52674L,52675L,52676L,52677L,52678L,52679L,52680L,52681L,52682L,
8509752683L,52684L,52685L,52686L,52687L,52688L,52689L,52690L,52691L,52692L,
8509852693L,52694L,52695L,52696L,52697L,52698L,52699L,52700L,52701L,52702L,
8509952703L,52704L,52705L,52706L,52707L,52708L,52709L,52710L,52711L,52712L,
8510052713L,52714L,52715L,52716L,52717L,52718L,52719L,52720L,52721L,52722L,
8510152723L,52724L,52725L,52726L,52727L,52728L,52729L,52730L,52731L,52732L,
8510252733L,52734L,52735L,52736L,52737L,52738L,52739L,52740L,52741L,52742L,
8510352743L,52744L,52745L,52746L,52747L,52748L,52749L,52750L,52751L,52752L,
8510452753L,52754L,52755L,52756L,52757L,52758L,52759L,52760L,52761L,52762L,
8510552763L,52764L,52765L,52766L,52767L,52768L,52769L,52770L,52771L,52772L,
8510652773L,52774L,52775L,52776L,52777L,52778L,52779L,52780L,52781L,52782L,
8510752783L,52784L,52785L,52786L,52787L,52788L,52789L,52790L,52791L,52792L,
8510852793L,52794L,52795L,52796L,52797L,52798L,52799L,52800L,52801L,52802L,
8510952803L,52804L,52805L,52806L,52807L,52808L,52809L,52810L,52811L,52812L,
8511052813L,52814L,52815L,52816L,52817L,52818L,52819L,52820L,52821L,52822L,
8511152823L,52824L,52825L,52826L,52827L,52828L,52829L,52830L,52831L,52832L,
8511252833L,52834L,52835L,52836L,52837L,52838L,52839L,52840L,52841L,52842L,
8511352843L,52844L,52845L,52846L,52847L,52848L,52849L,52850L,52851L,52852L,
8511452853L,52854L,52855L,52856L,52857L,52858L,52859L,52860L,52861L,52862L,
8511552863L,52864L,52865L,52866L,52867L,52868L,52869L,52870L,52871L,52872L,
8511652873L,52874L,52875L,52876L,52877L,52878L,52879L,52880L,52881L,52882L,
8511752883L,52884L,52885L,52886L,52887L,52888L,52889L,52890L,52891L,52892L,
8511852893L,52894L,52895L,52896L,52897L,52898L,52899L,52900L,52901L,52902L,
8511952903L,52904L,52905L,52906L,52907L,52908L,52909L,52910L,52911L,52912L,
8512052913L,52914L,52915L,52916L,52917L,52918L,52919L,52920L,52921L,52922L,
8512152923L,52924L,52925L,52926L,52927L,52928L,52929L,52930L,52931L,52932L,
8512252933L,52934L,52935L,52936L,52937L,52938L,52939L,52940L,52941L,52942L,
8512352943L,52944L,52945L,52946L,52947L,52948L,52949L,52950L,52951L,52952L,
8512452953L,52954L,52955L,52956L,52957L,52958L,52959L,52960L,52961L,52962L,
8512552963L,52964L,52965L,52966L,52967L,52968L,52969L,52970L,52971L,52972L,
8512652973L,52974L,52975L,52976L,52977L,52978L,52979L,52980L,52981L,52982L,
8512752983L,52984L,52985L,52986L,52987L,52988L,52989L,52990L,52991L,52992L,
8512852993L,52994L,52995L,52996L,52997L,52998L,52999L,53000L,53001L,53002L,
8512953003L,53004L,53005L,53006L,53007L,53008L,53009L,53010L,53011L,53012L,
8513053013L,53014L,53015L,53016L,53017L,53018L,53019L,53020L,53021L,53022L,
8513153023L,53024L,53025L,53026L,53027L,53028L,53029L,53030L,53031L,53032L,
8513253033L,53034L,53035L,53036L,53037L,53038L,53039L,53040L,53041L,53042L,
8513353043L,53044L,53045L,53046L,53047L,53048L,53049L,53050L,53051L,53052L,
8513453053L,53054L,53055L,53056L,53057L,53058L,53059L,53060L,53061L,53062L,
8513553063L,53064L,53065L,53066L,53067L,53068L,53069L,53070L,53071L,53072L,
8513653073L,53074L,53075L,53076L,53077L,53078L,53079L,53080L,53081L,53082L,
8513753083L,53084L,53085L,53086L,53087L,53088L,53089L,53090L,53091L,53092L,
8513853093L,53094L,53095L,53096L,53097L,53098L,53099L,53100L,53101L,53102L,
8513953103L,53104L,53105L,53106L,53107L,53108L,53109L,53110L,53111L,53112L,
8514053113L,53114L,53115L,53116L,53117L,53118L,53119L,53120L,53121L,53122L,
8514153123L,53124L,53125L,53126L,53127L,53128L,53129L,53130L,53131L,53132L,
8514253133L,53134L,53135L,53136L,53137L,53138L,53139L,53140L,53141L,53142L,
8514353143L,53144L,53145L,53146L,53147L,53148L,53149L,53150L,53151L,53152L,
8514453153L,53154L,53155L,53156L,53157L,53158L,53159L,53160L,53161L,53162L,
8514553163L,53164L,53165L,53166L,53167L,53168L,53169L,53170L,53171L,53172L,
8514653173L,53174L,53175L,53176L,53177L,53178L,53179L,53180L,53181L,53182L,
8514753183L,53184L,53185L,53186L,53187L,53188L,53189L,53190L,53191L,53192L,
8514853193L,53194L,53195L,53196L,53197L,53198L,53199L,53200L,53201L,53202L,
8514953203L,53204L,53205L,53206L,53207L,53208L,53209L,53210L,53211L,53212L,
8515053213L,53214L,53215L,53216L,53217L,53218L,53219L,53220L,53221L,53222L,
8515153223L,53224L,53225L,53226L,53227L,53228L,53229L,53230L,53231L,53232L,
8515253233L,53234L,53235L,53236L,53237L,53238L,53239L,53240L,53241L,53242L,
8515353243L,53244L,53245L,53246L,53247L,53248L,53249L,53250L,53251L,53252L,
8515453253L,53254L,53255L,53256L,53257L,53258L,53259L,53260L,53261L,53262L,
8515553263L,53264L,53265L,53266L,53267L,53268L,53269L,53270L,53271L,53272L,
8515653273L,53274L,53275L,53276L,53277L,53278L,53279L,53280L,53281L,53282L,
8515753283L,53284L,53285L,53286L,53287L,53288L,53289L,53290L,53291L,53292L,
8515853293L,53294L,53295L,53296L,53297L,53298L,53299L,53300L,53301L,53302L,
8515953303L,53304L,53305L,53306L,53307L,53308L,53309L,53310L,53311L,53312L,
8516053313L,53314L,53315L,53316L,53317L,53318L,53319L,53320L,53321L,53322L,
8516153323L,53324L,53325L,53326L,53327L,53328L,53329L,53330L,53331L,53332L,
8516253333L,53334L,53335L,53336L,53337L,53338L,53339L,53340L,53341L,53342L,
8516353343L,53344L,53345L,53346L,53347L,53348L,53349L,53350L,53351L,53352L,
8516453353L,53354L,53355L,53356L,53357L,53358L,53359L,53360L,53361L,53362L,
8516553363L,53364L,53365L,53366L,53367L,53368L,53369L,53370L,53371L,53372L,
8516653373L,53374L,53375L,53376L,53377L,53378L,53379L,53380L,53381L,53382L,
8516753383L,53384L,53385L,53386L,53387L,53388L,53389L,53390L,53391L,53392L,
8516853393L,53394L,53395L,53396L,53397L,53398L,53399L,53400L,53401L,53402L,
8516953403L,53404L,53405L,53406L,53407L,53408L,53409L,53410L,53411L,53412L,
8517053413L,53414L,53415L,53416L,53417L,53418L,53419L,53420L,53421L,53422L,
8517153423L,53424L,53425L,53426L,53427L,53428L,53429L,53430L,53431L,53432L,
8517253433L,53434L,53435L,53436L,53437L,53438L,53439L,53440L,53441L,53442L,
8517353443L,53444L,53445L,53446L,53447L,53448L,53449L,53450L,53451L,53452L,
8517453453L,53454L,53455L,53456L,53457L,53458L,53459L,53460L,53461L,53462L,
8517553463L,53464L,53465L,53466L,53467L,53468L,53469L,53470L,53471L,53472L,
8517653473L,53474L,53475L,53476L,53477L,53478L,53479L,53480L,53481L,53482L,
8517753483L,53484L,53485L,53486L,53487L,53488L,53489L,53490L,53491L,53492L,
8517853493L,53494L,53495L,53496L,53497L,53498L,53499L,53500L,53501L,53502L,
8517953503L,53504L,53505L,53506L,53507L,53508L,53509L,53510L,53511L,53512L,
8518053513L,53514L,53515L,53516L,53517L,53518L,53519L,53520L,53521L,53522L,
8518153523L,53524L,53525L,53526L,53527L,53528L,53529L,53530L,53531L,53532L,
8518253533L,53534L,53535L,53536L,53537L,53538L,53539L,53540L,53541L,53542L,
8518353543L,53544L,53545L,53546L,53547L,53548L,53549L,53550L,53551L,53552L,
8518453553L,53554L,53555L,53556L,53557L,53558L,53559L,53560L,53561L,53562L,
8518553563L,53564L,53565L,53566L,53567L,53568L,53569L,53570L,53571L,53572L,
8518653573L,53574L,53575L,53576L,53577L,53578L,53579L,53580L,53581L,53582L,
8518753583L,53584L,53585L,53586L,53587L,53588L,53589L,53590L,53591L,53592L,
8518853593L,53594L,53595L,53596L,53597L,53598L,53599L,53600L,53601L,53602L,
8518953603L,53604L,53605L,53606L,53607L,53608L,53609L,53610L,53611L,53612L,
8519053613L,53614L,53615L,53616L,53617L,53618L,53619L,53620L,53621L,53622L,
8519153623L,53624L,53625L,53626L,53627L,53628L,53629L,53630L,53631L,53632L,
8519253633L,53634L,53635L,53636L,53637L,53638L,53639L,53640L,53641L,53642L,
8519353643L,53644L,53645L,53646L,53647L,53648L,53649L,53650L,53651L,53652L,
8519453653L,53654L,53655L,53656L,53657L,53658L,53659L,53660L,53661L,53662L,
8519553663L,53664L,53665L,53666L,53667L,53668L,53669L,53670L,53671L,53672L,
8519653673L,53674L,53675L,53676L,53677L,53678L,53679L,53680L,53681L,53682L,
8519753683L,53684L,53685L,53686L,53687L,53688L,53689L,53690L,53691L,53692L,
8519853693L,53694L,53695L,53696L,53697L,53698L,53699L,53700L,53701L,53702L,
8519953703L,53704L,53705L,53706L,53707L,53708L,53709L,53710L,53711L,53712L,
8520053713L,53714L,53715L,53716L,53717L,53718L,53719L,53720L,53721L,53722L,
8520153723L,53724L,53725L,53726L,53727L,53728L,53729L,53730L,53731L,53732L,
8520253733L,53734L,53735L,53736L,53737L,53738L,53739L,53740L,53741L,53742L,
8520353743L,53744L,53745L,53746L,53747L,53748L,53749L,53750L,53751L,53752L,
8520453753L,53754L,53755L,53756L,53757L,53758L,53759L,53760L,53761L,53762L,
8520553763L,53764L,53765L,53766L,53767L,53768L,53769L,53770L,53771L,53772L,
8520653773L,53774L,53775L,53776L,53777L,53778L,53779L,53780L,53781L,53782L,
8520753783L,53784L,53785L,53786L,53787L,53788L,53789L,53790L,53791L,53792L,
8520853793L,53794L,53795L,53796L,53797L,53798L,53799L,53800L,53801L,53802L,
8520953803L,53804L,53805L,53806L,53807L,53808L,53809L,53810L,53811L,53812L,
8521053813L,53814L,53815L,53816L,53817L,53818L,53819L,53820L,53821L,53822L,
8521153823L,53824L,53825L,53826L,53827L,53828L,53829L,53830L,53831L,53832L,
8521253833L,53834L,53835L,53836L,53837L,53838L,53839L,53840L,53841L,53842L,
8521353843L,53844L,53845L,53846L,53847L,53848L,53849L,53850L,53851L,53852L,
8521453853L,53854L,53855L,53856L,53857L,53858L,53859L,53860L,53861L,53862L,
8521553863L,53864L,53865L,53866L,53867L,53868L,53869L,53870L,53871L,53872L,
8521653873L,53874L,53875L,53876L,53877L,53878L,53879L,53880L,53881L,53882L,
8521753883L,53884L,53885L,53886L,53887L,53888L,53889L,53890L,53891L,53892L,
8521853893L,53894L,53895L,53896L,53897L,53898L,53899L,53900L,53901L,53902L,
8521953903L,53904L,53905L,53906L,53907L,53908L,53909L,53910L,53911L,53912L,
8522053913L,53914L,53915L,53916L,53917L,53918L,53919L,53920L,53921L,53922L,
8522153923L,53924L,53925L,53926L,53927L,53928L,53929L,53930L,53931L,53932L,
8522253933L,53934L,53935L,53936L,53937L,53938L,53939L,53940L,53941L,53942L,
8522353943L,53944L,53945L,53946L,53947L,53948L,53949L,53950L,53951L,53952L,
8522453953L,53954L,53955L,53956L,53957L,53958L,53959L,53960L,53961L,53962L,
8522553963L,53964L,53965L,53966L,53967L,53968L,53969L,53970L,53971L,53972L,
8522653973L,53974L,53975L,53976L,53977L,53978L,53979L,53980L,53981L,53982L,
8522753983L,53984L,53985L,53986L,53987L,53988L,53989L,53990L,53991L,53992L,
8522853993L,53994L,53995L,53996L,53997L,53998L,53999L,54000L,54001L,54002L,
8522954003L,54004L,54005L,54006L,54007L,54008L,54009L,54010L,54011L,54012L,
8523054013L,54014L,54015L,54016L,54017L,54018L,54019L,54020L,54021L,54022L,
8523154023L,54024L,54025L,54026L,54027L,54028L,54029L,54030L,54031L,54032L,
8523254033L,54034L,54035L,54036L,54037L,54038L,54039L,54040L,54041L,54042L,
8523354043L,54044L,54045L,54046L,54047L,54048L,54049L,54050L,54051L,54052L,
8523454053L,54054L,54055L,54056L,54057L,54058L,54059L,54060L,54061L,54062L,
8523554063L,54064L,54065L,54066L,54067L,54068L,54069L,54070L,54071L,54072L,
8523654073L,54074L,54075L,54076L,54077L,54078L,54079L,54080L,54081L,54082L,
8523754083L,54084L,54085L,54086L,54087L,54088L,54089L,54090L,54091L,54092L,
8523854093L,54094L,54095L,54096L,54097L,54098L,54099L,54100L,54101L,54102L,
8523954103L,54104L,54105L,54106L,54107L,54108L,54109L,54110L,54111L,54112L,
8524054113L,54114L,54115L,54116L,54117L,54118L,54119L,54120L,54121L,54122L,
8524154123L,54124L,54125L,54126L,54127L,54128L,54129L,54130L,54131L,54132L,
8524254133L,54134L,54135L,54136L,54137L,54138L,54139L,54140L,54141L,54142L,
8524354143L,54144L,54145L,54146L,54147L,54148L,54149L,54150L,54151L,54152L,
8524454153L,54154L,54155L,54156L,54157L,54158L,54159L,54160L,54161L,54162L,
8524554163L,54164L,54165L,54166L,54167L,54168L,54169L,54170L,54171L,54172L,
8524654173L,54174L,54175L,54176L,54177L,54178L,54179L,54180L,54181L,54182L,
8524754183L,54184L,54185L,54186L,54187L,54188L,54189L,54190L,54191L,54192L,
8524854193L,54194L,54195L,54196L,54197L,54198L,54199L,54200L,54201L,54202L,
8524954203L,54204L,54205L,54206L,54207L,54208L,54209L,54210L,54211L,54212L,
8525054213L,54214L,54215L,54216L,54217L,54218L,54219L,54220L,54221L,54222L,
8525154223L,54224L,54225L,54226L,54227L,54228L,54229L,54230L,54231L,54232L,
8525254233L,54234L,54235L,54236L,54237L,54238L,54239L,54240L,54241L,54242L,
8525354243L,54244L,54245L,54246L,54247L,54248L,54249L,54250L,54251L,54252L,
8525454253L,54254L,54255L,54256L,54257L,54258L,54259L,54260L,54261L,54262L,
8525554263L,54264L,54265L,54266L,54267L,54268L,54269L,54270L,54271L,54272L,
8525654273L,54274L,54275L,54276L,54277L,54278L,54279L,54280L,54281L,54282L,
8525754283L,54284L,54285L,54286L,54287L,54288L,54289L,54290L,54291L,54292L,
8525854293L,54294L,54295L,54296L,54297L,54298L,54299L,54300L,54301L,54302L,
8525954303L,54304L,54305L,54306L,54307L,54308L,54309L,54310L,54311L,54312L,
8526054313L,54314L,54315L,54316L,54317L,54318L,54319L,54320L,54321L,54322L,
8526154323L,54324L,54325L,54326L,54327L,54328L,54329L,54330L,54331L,54332L,
8526254333L,54334L,54335L,54336L,54337L,54338L,54339L,54340L,54341L,54342L,
8526354343L,54344L,54345L,54346L,54347L,54348L,54349L,54350L,54351L,54352L,
8526454353L,54354L,54355L,54356L,54357L,54358L,54359L,54360L,54361L,54362L,
8526554363L,54364L,54365L,54366L,54367L,54368L,54369L,54370L,54371L,54372L,
8526654373L,54374L,54375L,54376L,54377L,54378L,54379L,54380L,54381L,54382L,
8526754383L,54384L,54385L,54386L,54387L,54388L,54389L,54390L,54391L,54392L,
8526854393L,54394L,54395L,54396L,54397L,54398L,54399L,54400L,54401L,54402L,
8526954403L,54404L,54405L,54406L,54407L,54408L,54409L,54410L,54411L,54412L,
8527054413L,54414L,54415L,54416L,54417L,54418L,54419L,54420L,54421L,54422L,
8527154423L,54424L,54425L,54426L,54427L,54428L,54429L,54430L,54431L,54432L,
8527254433L,54434L,54435L,54436L,54437L,54438L,54439L,54440L,54441L,54442L,
8527354443L,54444L,54445L,54446L,54447L,54448L,54449L,54450L,54451L,54452L,
8527454453L,54454L,54455L,54456L,54457L,54458L,54459L,54460L,54461L,54462L,
8527554463L,54464L,54465L,54466L,54467L,54468L,54469L,54470L,54471L,54472L,
8527654473L,54474L,54475L,54476L,54477L,54478L,54479L,54480L,54481L,54482L,
8527754483L,54484L,54485L,54486L,54487L,54488L,54489L,54490L,54491L,54492L,
8527854493L,54494L,54495L,54496L,54497L,54498L,54499L,54500L,54501L,54502L,
8527954503L,54504L,54505L,54506L,54507L,54508L,54509L,54510L,54511L,54512L,
8528054513L,54514L,54515L,54516L,54517L,54518L,54519L,54520L,54521L,54522L,
8528154523L,54524L,54525L,54526L,54527L,54528L,54529L,54530L,54531L,54532L,
8528254533L,54534L,54535L,54536L,54537L,54538L,54539L,54540L,54541L,54542L,
8528354543L,54544L,54545L,54546L,54547L,54548L,54549L,54550L,54551L,54552L,
8528454553L,54554L,54555L,54556L,54557L,54558L,54559L,54560L,54561L,54562L,
8528554563L,54564L,54565L,54566L,54567L,54568L,54569L,54570L,54571L,54572L,
8528654573L,54574L,54575L,54576L,54577L,54578L,54579L,54580L,54581L,54582L,
8528754583L,54584L,54585L,54586L,54587L,54588L,54589L,54590L,54591L,54592L,
8528854593L,54594L,54595L,54596L,54597L,54598L,54599L,54600L,54601L,54602L,
8528954603L,54604L,54605L,54606L,54607L,54608L,54609L,54610L,54611L,54612L,
8529054613L,54614L,54615L,54616L,54617L,54618L,54619L,54620L,54621L,54622L,
8529154623L,54624L,54625L,54626L,54627L,54628L,54629L,54630L,54631L,54632L,
8529254633L,54634L,54635L,54636L,54637L,54638L,54639L,54640L,54641L,54642L,
8529354643L,54644L,54645L,54646L,54647L,54648L,54649L,54650L,54651L,54652L,
8529454653L,54654L,54655L,54656L,54657L,54658L,54659L,54660L,54661L,54662L,
8529554663L,54664L,54665L,54666L,54667L,54668L,54669L,54670L,54671L,54672L,
8529654673L,54674L,54675L,54676L,54677L,54678L,54679L,54680L,54681L,54682L,
8529754683L,54684L,54685L,54686L,54687L,54688L,54689L,54690L,54691L,54692L,
8529854693L,54694L,54695L,54696L,54697L,54698L,54699L,54700L,54701L,54702L,
8529954703L,54704L,54705L,54706L,54707L,54708L,54709L,54710L,54711L,54712L,
8530054713L,54714L,54715L,54716L,54717L,54718L,54719L,54720L,54721L,54722L,
8530154723L,54724L,54725L,54726L,54727L,54728L,54729L,54730L,54731L,54732L,
8530254733L,54734L,54735L,54736L,54737L,54738L,54739L,54740L,54741L,54742L,
8530354743L,54744L,54745L,54746L,54747L,54748L,54749L,54750L,54751L,54752L,
8530454753L,54754L,54755L,54756L,54757L,54758L,54759L,54760L,54761L,54762L,
8530554763L,54764L,54765L,54766L,54767L,54768L,54769L,54770L,54771L,54772L,
8530654773L,54774L,54775L,54776L,54777L,54778L,54779L,54780L,54781L,54782L,
8530754783L,54784L,54785L,54786L,54787L,54788L,54789L,54790L,54791L,54792L,
8530854793L,54794L,54795L,54796L,54797L,54798L,54799L,54800L,54801L,54802L,
8530954803L,54804L,54805L,54806L,54807L,54808L,54809L,54810L,54811L,54812L,
8531054813L,54814L,54815L,54816L,54817L,54818L,54819L,54820L,54821L,54822L,
8531154823L,54824L,54825L,54826L,54827L,54828L,54829L,54830L,54831L,54832L,
8531254833L,54834L,54835L,54836L,54837L,54838L,54839L,54840L,54841L,54842L,
8531354843L,54844L,54845L,54846L,54847L,54848L,54849L,54850L,54851L,54852L,
8531454853L,54854L,54855L,54856L,54857L,54858L,54859L,54860L,54861L,54862L,
8531554863L,54864L,54865L,54866L,54867L,54868L,54869L,54870L,54871L,54872L,
8531654873L,54874L,54875L,54876L,54877L,54878L,54879L,54880L,54881L,54882L,
8531754883L,54884L,54885L,54886L,54887L,54888L,54889L,54890L,54891L,54892L,
8531854893L,54894L,54895L,54896L,54897L,54898L,54899L,54900L,54901L,54902L,
8531954903L,54904L,54905L,54906L,54907L,54908L,54909L,54910L,54911L,54912L,
8532054913L,54914L,54915L,54916L,54917L,54918L,54919L,54920L,54921L,54922L,
8532154923L,54924L,54925L,54926L,54927L,54928L,54929L,54930L,54931L,54932L,
8532254933L,54934L,54935L,54936L,54937L,54938L,54939L,54940L,54941L,54942L,
8532354943L,54944L,54945L,54946L,54947L,54948L,54949L,54950L,54951L,54952L,
8532454953L,54954L,54955L,54956L,54957L,54958L,54959L,54960L,54961L,54962L,
8532554963L,54964L,54965L,54966L,54967L,54968L,54969L,54970L,54971L,54972L,
8532654973L,54974L,54975L,54976L,54977L,54978L,54979L,54980L,54981L,54982L,
8532754983L,54984L,54985L,54986L,54987L,54988L,54989L,54990L,54991L,54992L,
8532854993L,54994L,54995L,54996L,54997L,54998L,54999L,55000L,55001L,55002L,
8532955003L,55004L,55005L,55006L,55007L,55008L,55009L,55010L,55011L,55012L,
8533055013L,55014L,55015L,55016L,55017L,55018L,55019L,55020L,55021L,55022L,
8533155023L,55024L,55025L,55026L,55027L,55028L,55029L,55030L,55031L,55032L,
8533255033L,55034L,55035L,55036L,55037L,55038L,55039L,55040L,55041L,55042L,
8533355043L,55044L,55045L,55046L,55047L,55048L,55049L,55050L,55051L,55052L,
8533455053L,55054L,55055L,55056L,55057L,55058L,55059L,55060L,55061L,55062L,
8533555063L,55064L,55065L,55066L,55067L,55068L,55069L,55070L,55071L,55072L,
8533655073L,55074L,55075L,55076L,55077L,55078L,55079L,55080L,55081L,55082L,
8533755083L,55084L,55085L,55086L,55087L,55088L,55089L,55090L,55091L,55092L,
8533855093L,55094L,55095L,55096L,55097L,55098L,55099L,55100L,55101L,55102L,
8533955103L,55104L,55105L,55106L,55107L,55108L,55109L,55110L,55111L,55112L,
8534055113L,55114L,55115L,55116L,55117L,55118L,55119L,55120L,55121L,55122L,
8534155123L,55124L,55125L,55126L,55127L,55128L,55129L,55130L,55131L,55132L,
8534255133L,55134L,55135L,55136L,55137L,55138L,55139L,55140L,55141L,55142L,
8534355143L,55144L,55145L,55146L,55147L,55148L,55149L,55150L,55151L,55152L,
8534455153L,55154L,55155L,55156L,55157L,55158L,55159L,55160L,55161L,55162L,
8534555163L,55164L,55165L,55166L,55167L,55168L,55169L,55170L,55171L,55172L,
8534655173L,55174L,55175L,55176L,55177L,55178L,55179L,55180L,55181L,55182L,
8534755183L,55184L,55185L,55186L,55187L,55188L,55189L,55190L,55191L,55192L,
8534855193L,55194L,55195L,55196L,55197L,55198L,55199L,55200L,55201L,55202L,
8534955203L,55204L,55205L,55206L,55207L,55208L,55209L,55210L,55211L,55212L,
8535055213L,55214L,55215L,55216L,55217L,55218L,55219L,55220L,55221L,55222L,
8535155223L,55224L,55225L,55226L,55227L,55228L,55229L,55230L,55231L,55232L,
8535255233L,55234L,55235L,55236L,55237L,55238L,55239L,55240L,55241L,55242L,
8535355243L,55244L,55245L,55246L,55247L,55248L,55249L,55250L,55251L,55252L,
8535455253L,55254L,55255L,55256L,55257L,55258L,55259L,55260L,55261L,55262L,
8535555263L,55264L,55265L,55266L,55267L,55268L,55269L,55270L,55271L,55272L,
8535655273L,55274L,55275L,55276L,55277L,55278L,55279L,55280L,55281L,55282L,
8535755283L,55284L,55285L,55286L,55287L,55288L,55289L,55290L,55291L,55292L,
8535855293L,55294L,55295L,55296L,55297L,55298L,55299L,55300L,55301L,55302L,
8535955303L,55304L,55305L,55306L,55307L,55308L,55309L,55310L,55311L,55312L,
8536055313L,55314L,55315L,55316L,55317L,55318L,55319L,55320L,55321L,55322L,
8536155323L,55324L,55325L,55326L,55327L,55328L,55329L,55330L,55331L,55332L,
8536255333L,55334L,55335L,55336L,55337L,55338L,55339L,55340L,55341L,55342L,
8536355343L,55344L,55345L,55346L,55347L,55348L,55349L,55350L,55351L,55352L,
8536455353L,55354L,55355L,55356L,55357L,55358L,55359L,55360L,55361L,55362L,
8536555363L,55364L,55365L,55366L,55367L,55368L,55369L,55370L,55371L,55372L,
8536655373L,55374L,55375L,55376L,55377L,55378L,55379L,55380L,55381L,55382L,
8536755383L,55384L,55385L,55386L,55387L,55388L,55389L,55390L,55391L,55392L,
8536855393L,55394L,55395L,55396L,55397L,55398L,55399L,55400L,55401L,55402L,
8536955403L,55404L,55405L,55406L,55407L,55408L,55409L,55410L,55411L,55412L,
8537055413L,55414L,55415L,55416L,55417L,55418L,55419L,55420L,55421L,55422L,
8537155423L,55424L,55425L,55426L,55427L,55428L,55429L,55430L,55431L,55432L,
8537255433L,55434L,55435L,55436L,55437L,55438L,55439L,55440L,55441L,55442L,
8537355443L,55444L,55445L,55446L,55447L,55448L,55449L,55450L,55451L,55452L,
8537455453L,55454L,55455L,55456L,55457L,55458L,55459L,55460L,55461L,55462L,
8537555463L,55464L,55465L,55466L,55467L,55468L,55469L,55470L,55471L,55472L,
8537655473L,55474L,55475L,55476L,55477L,55478L,55479L,55480L,55481L,55482L,
8537755483L,55484L,55485L,55486L,55487L,55488L,55489L,55490L,55491L,55492L,
8537855493L,55494L,55495L,55496L,55497L,55498L,55499L,55500L,55501L,55502L,
8537955503L,55504L,55505L,55506L,55507L,55508L,55509L,55510L,55511L,55512L,
8538055513L,55514L,55515L,55516L,55517L,55518L,55519L,55520L,55521L,55522L,
8538155523L,55524L,55525L,55526L,55527L,55528L,55529L,55530L,55531L,55532L,
8538255533L,55534L,55535L,55536L,55537L,55538L,55539L,55540L,55541L,55542L,
8538355543L,55544L,55545L,55546L,55547L,55548L,55549L,55550L,55551L,55552L,
8538455553L,55554L,55555L,55556L,55557L,55558L,55559L,55560L,55561L,55562L,
8538555563L,55564L,55565L,55566L,55567L,55568L,55569L,55570L,55571L,55572L,
8538655573L,55574L,55575L,55576L,55577L,55578L,55579L,55580L,55581L,55582L,
8538755583L,55584L,55585L,55586L,55587L,55588L,55589L,55590L,55591L,55592L,
8538855593L,55594L,55595L,55596L,55597L,55598L,55599L,55600L,55601L,55602L,
8538955603L,55604L,55605L,55606L,55607L,55608L,55609L,55610L,55611L,55612L,
8539055613L,55614L,55615L,55616L,55617L,55618L,55619L,55620L,55621L,55622L,
8539155623L,55624L,55625L,55626L,55627L,55628L,55629L,55630L,55631L,55632L,
8539255633L,55634L,55635L,55636L,55637L,55638L,55639L,55640L,55641L,55642L,
8539355643L,55644L,55645L,55646L,55647L,55648L,55649L,55650L,55651L,55652L,
8539455653L,55654L,55655L,55656L,55657L,55658L,55659L,55660L,55661L,55662L,
8539555663L,55664L,55665L,55666L,55667L,55668L,55669L,55670L,55671L,55672L,
8539655673L,55674L,55675L,55676L,55677L,55678L,55679L,55680L,55681L,55682L,
8539755683L,55684L,55685L,55686L,55687L,55688L,55689L,55690L,55691L,55692L,
8539855693L,55694L,55695L,55696L,55697L,55698L,55699L,55700L,55701L,55702L,
8539955703L,55704L,55705L,55706L,55707L,55708L,55709L,55710L,55711L,55712L,
8540055713L,55714L,55715L,55716L,55717L,55718L,55719L,55720L,55721L,55722L,
8540155723L,55724L,55725L,55726L,55727L,55728L,55729L,55730L,55731L,55732L,
8540255733L,55734L,55735L,55736L,55737L,55738L,55739L,55740L,55741L,55742L,
8540355743L,55744L,55745L,55746L,55747L,55748L,55749L,55750L,55751L,55752L,
8540455753L,55754L,55755L,55756L,55757L,55758L,55759L,55760L,55761L,55762L,
8540555763L,55764L,55765L,55766L,55767L,55768L,55769L,55770L,55771L,55772L,
8540655773L,55774L,55775L,55776L,55777L,55778L,55779L,55780L,55781L,55782L,
8540755783L,55784L,55785L,55786L,55787L,55788L,55789L,55790L,55791L,55792L,
8540855793L,55794L,55795L,55796L,55797L,55798L,55799L,55800L,55801L,55802L,
8540955803L,55804L,55805L,55806L,55807L,55808L,55809L,55810L,55811L,55812L,
8541055813L,55814L,55815L,55816L,55817L,55818L,55819L,55820L,55821L,55822L,
8541155823L,55824L,55825L,55826L,55827L,55828L,55829L,55830L,55831L,55832L,
8541255833L,55834L,55835L,55836L,55837L,55838L,55839L,55840L,55841L,55842L,
8541355843L,55844L,55845L,55846L,55847L,55848L,55849L,55850L,55851L,55852L,
8541455853L,55854L,55855L,55856L,55857L,55858L,55859L,55860L,55861L,55862L,
8541555863L,55864L,55865L,55866L,55867L,55868L,55869L,55870L,55871L,55872L,
8541655873L,55874L,55875L,55876L,55877L,55878L,55879L,55880L,55881L,55882L,
8541755883L,55884L,55885L,55886L,55887L,55888L,55889L,55890L,55891L,55892L,
8541855893L,55894L,55895L,55896L,55897L,55898L,55899L,55900L,55901L,55902L,
8541955903L,55904L,55905L,55906L,55907L,55908L,55909L,55910L,55911L,55912L,
8542055913L,55914L,55915L,55916L,55917L,55918L,55919L,55920L,55921L,55922L,
8542155923L,55924L,55925L,55926L,55927L,55928L,55929L,55930L,55931L,55932L,
8542255933L,55934L,55935L,55936L,55937L,55938L,55939L,55940L,55941L,55942L,
8542355943L,55944L,55945L,55946L,55947L,55948L,55949L,55950L,55951L,55952L,
8542455953L,55954L,55955L,55956L,55957L,55958L,55959L,55960L,55961L,55962L,
8542555963L,55964L,55965L,55966L,55967L,55968L,55969L,55970L,55971L,55972L,
8542655973L,55974L,55975L,55976L,55977L,55978L,55979L,55980L,55981L,55982L,
8542755983L,55984L,55985L,55986L,55987L,55988L,55989L,55990L,55991L,55992L,
8542855993L,55994L,55995L,55996L,55997L,55998L,55999L,56000L,56001L,56002L,
8542956003L,56004L,56005L,56006L,56007L,56008L,56009L,56010L,56011L,56012L,
8543056013L,56014L,56015L,56016L,56017L,56018L,56019L,56020L,56021L,56022L,
8543156023L,56024L,56025L,56026L,56027L,56028L,56029L,56030L,56031L,56032L,
8543256033L,56034L,56035L,56036L,56037L,56038L,56039L,56040L,56041L,56042L,
8543356043L,56044L,56045L,56046L,56047L,56048L,56049L,56050L,56051L,56052L,
8543456053L,56054L,56055L,56056L,56057L,56058L,56059L,56060L,56061L,56062L,
8543556063L,56064L,56065L,56066L,56067L,56068L,56069L,56070L,56071L,56072L,
8543656073L,56074L,56075L,56076L,56077L,56078L,56079L,56080L,56081L,56082L,
8543756083L,56084L,56085L,56086L,56087L,56088L,56089L,56090L,56091L,56092L,
8543856093L,56094L,56095L,56096L,56097L,56098L,56099L,56100L,56101L,56102L,
8543956103L,56104L,56105L,56106L,56107L,56108L,56109L,56110L,56111L,56112L,
8544056113L,56114L,56115L,56116L,56117L,56118L,56119L,56120L,56121L,56122L,
8544156123L,56124L,56125L,56126L,56127L,56128L,56129L,56130L,56131L,56132L,
8544256133L,56134L,56135L,56136L,56137L,56138L,56139L,56140L,56141L,56142L,
8544356143L,56144L,56145L,56146L,56147L,56148L,56149L,56150L,56151L,56152L,
8544456153L,56154L,56155L,56156L,56157L,56158L,56159L,56160L,56161L,56162L,
8544556163L,56164L,56165L,56166L,56167L,56168L,56169L,56170L,56171L,56172L,
8544656173L,56174L,56175L,56176L,56177L,56178L,56179L,56180L,56181L,56182L,
8544756183L,56184L,56185L,56186L,56187L,56188L,56189L,56190L,56191L,56192L,
8544856193L,56194L,56195L,56196L,56197L,56198L,56199L,56200L,56201L,56202L,
8544956203L,56204L,56205L,56206L,56207L,56208L,56209L,56210L,56211L,56212L,
8545056213L,56214L,56215L,56216L,56217L,56218L,56219L,56220L,56221L,56222L,
8545156223L,56224L,56225L,56226L,56227L,56228L,56229L,56230L,56231L,56232L,
8545256233L,56234L,56235L,56236L,56237L,56238L,56239L,56240L,56241L,56242L,
8545356243L,56244L,56245L,56246L,56247L,56248L,56249L,56250L,56251L,56252L,
8545456253L,56254L,56255L,56256L,56257L,56258L,56259L,56260L,56261L,56262L,
8545556263L,56264L,56265L,56266L,56267L,56268L,56269L,56270L,56271L,56272L,
8545656273L,56274L,56275L,56276L,56277L,56278L,56279L,56280L,56281L,56282L,
8545756283L,56284L,56285L,56286L,56287L,56288L,56289L,56290L,56291L,56292L,
8545856293L,56294L,56295L,56296L,56297L,56298L,56299L,56300L,56301L,56302L,
8545956303L,56304L,56305L,56306L,56307L,56308L,56309L,56310L,56311L,56312L,
8546056313L,56314L,56315L,56316L,56317L,56318L,56319L,56320L,56321L,56322L,
8546156323L,56324L,56325L,56326L,56327L,56328L,56329L,56330L,56331L,56332L,
8546256333L,56334L,56335L,56336L,56337L,56338L,56339L,56340L,56341L,56342L,
8546356343L,56344L,56345L,56346L,56347L,56348L,56349L,56350L,56351L,56352L,
8546456353L,56354L,56355L,56356L,56357L,56358L,56359L,56360L,56361L,56362L,
8546556363L,56364L,56365L,56366L,56367L,56368L,56369L,56370L,56371L,56372L,
8546656373L,56374L,56375L,56376L,56377L,56378L,56379L,56380L,56381L,56382L,
8546756383L,56384L,56385L,56386L,56387L,56388L,56389L,56390L,56391L,56392L,
8546856393L,56394L,56395L,56396L,56397L,56398L,56399L,56400L,56401L,56402L,
8546956403L,56404L,56405L,56406L,56407L,56408L,56409L,56410L,56411L,56412L,
8547056413L,56414L,56415L,56416L,56417L,56418L,56419L,56420L,56421L,56422L,
8547156423L,56424L,56425L,56426L,56427L,56428L,56429L,56430L,56431L,56432L,
8547256433L,56434L,56435L,56436L,56437L,56438L,56439L,56440L,56441L,56442L,
8547356443L,56444L,56445L,56446L,56447L,56448L,56449L,56450L,56451L,56452L,
8547456453L,56454L,56455L,56456L,56457L,56458L,56459L,56460L,56461L,56462L,
8547556463L,56464L,56465L,56466L,56467L,56468L,56469L,56470L,56471L,56472L,
8547656473L,56474L,56475L,56476L,56477L,56478L,56479L,56480L,56481L,56482L,
8547756483L,56484L,56485L,56486L,56487L,56488L,56489L,56490L,56491L,56492L,
8547856493L,56494L,56495L,56496L,56497L,56498L,56499L,56500L,56501L,56502L,
8547956503L,56504L,56505L,56506L,56507L,56508L,56509L,56510L,56511L,56512L,
8548056513L,56514L,56515L,56516L,56517L,56518L,56519L,56520L,56521L,56522L,
8548156523L,56524L,56525L,56526L,56527L,56528L,56529L,56530L,56531L,56532L,
8548256533L,56534L,56535L,56536L,56537L,56538L,56539L,56540L,56541L,56542L,
8548356543L,56544L,56545L,56546L,56547L,56548L,56549L,56550L,56551L,56552L,
8548456553L,56554L,56555L,56556L,56557L,56558L,56559L,56560L,56561L,56562L,
8548556563L,56564L,56565L,56566L,56567L,56568L,56569L,56570L,56571L,56572L,
8548656573L,56574L,56575L,56576L,56577L,56578L,56579L,56580L,56581L,56582L,
8548756583L,56584L,56585L,56586L,56587L,56588L,56589L,56590L,56591L,56592L,
8548856593L,56594L,56595L,56596L,56597L,56598L,56599L,56600L,56601L,56602L,
8548956603L,56604L,56605L,56606L,56607L,56608L,56609L,56610L,56611L,56612L,
8549056613L,56614L,56615L,56616L,56617L,56618L,56619L,56620L,56621L,56622L,
8549156623L,56624L,56625L,56626L,56627L,56628L,56629L,56630L,56631L,56632L,
8549256633L,56634L,56635L,56636L,56637L,56638L,56639L,56640L,56641L,56642L,
8549356643L,56644L,56645L,56646L,56647L,56648L,56649L,56650L,56651L,56652L,
8549456653L,56654L,56655L,56656L,56657L,56658L,56659L,56660L,56661L,56662L,
8549556663L,56664L,56665L,56666L,56667L,56668L,56669L,56670L,56671L,56672L,
8549656673L,56674L,56675L,56676L,56677L,56678L,56679L,56680L,56681L,56682L,
8549756683L,56684L,56685L,56686L,56687L,56688L,56689L,56690L,56691L,56692L,
8549856693L,56694L,56695L,56696L,56697L,56698L,56699L,56700L,56701L,56702L,
8549956703L,56704L,56705L,56706L,56707L,56708L,56709L,56710L,56711L,56712L,
8550056713L,56714L,56715L,56716L,56717L,56718L,56719L,56720L,56721L,56722L,
8550156723L,56724L,56725L,56726L,56727L,56728L,56729L,56730L,56731L,56732L,
8550256733L,56734L,56735L,56736L,56737L,56738L,56739L,56740L,56741L,56742L,
8550356743L,56744L,56745L,56746L,56747L,56748L,56749L,56750L,56751L,56752L,
8550456753L,56754L,56755L,56756L,56757L,56758L,56759L,56760L,56761L,56762L,
8550556763L,56764L,56765L,56766L,56767L,56768L,56769L,56770L,56771L,56772L,
8550656773L,56774L,56775L,56776L,56777L,56778L,56779L,56780L,56781L,56782L,
8550756783L,56784L,56785L,56786L,56787L,56788L,56789L,56790L,56791L,56792L,
8550856793L,56794L,56795L,56796L,56797L,56798L,56799L,56800L,56801L,56802L,
8550956803L,56804L,56805L,56806L,56807L,56808L,56809L,56810L,56811L,56812L,
8551056813L,56814L,56815L,56816L,56817L,56818L,56819L,56820L,56821L,56822L,
8551156823L,56824L,56825L,56826L,56827L,56828L,56829L,56830L,56831L,56832L,
8551256833L,56834L,56835L,56836L,56837L,56838L,56839L,56840L,56841L,56842L,
8551356843L,56844L,56845L,56846L,56847L,56848L,56849L,56850L,56851L,56852L,
8551456853L,56854L,56855L,56856L,56857L,56858L,56859L,56860L,56861L,56862L,
8551556863L,56864L,56865L,56866L,56867L,56868L,56869L,56870L,56871L,56872L,
8551656873L,56874L,56875L,56876L,56877L,56878L,56879L,56880L,56881L,56882L,
8551756883L,56884L,56885L,56886L,56887L,56888L,56889L,56890L,56891L,56892L,
8551856893L,56894L,56895L,56896L,56897L,56898L,56899L,56900L,56901L,56902L,
8551956903L,56904L,56905L,56906L,56907L,56908L,56909L,56910L,56911L,56912L,
8552056913L,56914L,56915L,56916L,56917L,56918L,56919L,56920L,56921L,56922L,
8552156923L,56924L,56925L,56926L,56927L,56928L,56929L,56930L,56931L,56932L,
8552256933L,56934L,56935L,56936L,56937L,56938L,56939L,56940L,56941L,56942L,
8552356943L,56944L,56945L,56946L,56947L,56948L,56949L,56950L,56951L,56952L,
8552456953L,56954L,56955L,56956L,56957L,56958L,56959L,56960L,56961L,56962L,
8552556963L,56964L,56965L,56966L,56967L,56968L,56969L,56970L,56971L,56972L,
8552656973L,56974L,56975L,56976L,56977L,56978L,56979L,56980L,56981L,56982L,
8552756983L,56984L,56985L,56986L,56987L,56988L,56989L,56990L,56991L,56992L,
8552856993L,56994L,56995L,56996L,56997L,56998L,56999L,57000L,57001L,57002L,
8552957003L,57004L,57005L,57006L,57007L,57008L,57009L,57010L,57011L,57012L,
8553057013L,57014L,57015L,57016L,57017L,57018L,57019L,57020L,57021L,57022L,
8553157023L,57024L,57025L,57026L,57027L,57028L,57029L,57030L,57031L,57032L,
8553257033L,57034L,57035L,57036L,57037L,57038L,57039L,57040L,57041L,57042L,
8553357043L,57044L,57045L,57046L,57047L,57048L,57049L,57050L,57051L,57052L,
8553457053L,57054L,57055L,57056L,57057L,57058L,57059L,57060L,57061L,57062L,
8553557063L,57064L,57065L,57066L,57067L,57068L,57069L,57070L,57071L,57072L,
8553657073L,57074L,57075L,57076L,57077L,57078L,57079L,57080L,57081L,57082L,
8553757083L,57084L,57085L,57086L,57087L,57088L,57089L,57090L,57091L,57092L,
8553857093L,57094L,57095L,57096L,57097L,57098L,57099L,57100L,57101L,57102L,
8553957103L,57104L,57105L,57106L,57107L,57108L,57109L,57110L,57111L,57112L,
8554057113L,57114L,57115L,57116L,57117L,57118L,57119L,57120L,57121L,57122L,
8554157123L,57124L,57125L,57126L,57127L,57128L,57129L,57130L,57131L,57132L,
8554257133L,57134L,57135L,57136L,57137L,57138L,57139L,57140L,57141L,57142L,
8554357143L,57144L,57145L,57146L,57147L,57148L,57149L,57150L,57151L,57152L,
8554457153L,57154L,57155L,57156L,57157L,57158L,57159L,57160L,57161L,57162L,
8554557163L,57164L,57165L,57166L,57167L,57168L,57169L,57170L,57171L,57172L,
8554657173L,57174L,57175L,57176L,57177L,57178L,57179L,57180L,57181L,57182L,
8554757183L,57184L,57185L,57186L,57187L,57188L,57189L,57190L,57191L,57192L,
8554857193L,57194L,57195L,57196L,57197L,57198L,57199L,57200L,57201L,57202L,
8554957203L,57204L,57205L,57206L,57207L,57208L,57209L,57210L,57211L,57212L,
8555057213L,57214L,57215L,57216L,57217L,57218L,57219L,57220L,57221L,57222L,
8555157223L,57224L,57225L,57226L,57227L,57228L,57229L,57230L,57231L,57232L,
8555257233L,57234L,57235L,57236L,57237L,57238L,57239L,57240L,57241L,57242L,
8555357243L,57244L,57245L,57246L,57247L,57248L,57249L,57250L,57251L,57252L,
8555457253L,57254L,57255L,57256L,57257L,57258L,57259L,57260L,57261L,57262L,
8555557263L,57264L,57265L,57266L,57267L,57268L,57269L,57270L,57271L,57272L,
8555657273L,57274L,57275L,57276L,57277L,57278L,57279L,57280L,57281L,57282L,
8555757283L,57284L,57285L,57286L,57287L,57288L,57289L,57290L,57291L,57292L,
8555857293L,57294L,57295L,57296L,57297L,57298L,57299L,57300L,57301L,57302L,
8555957303L,57304L,57305L,57306L,57307L,57308L,57309L,57310L,57311L,57312L,
8556057313L,57314L,57315L,57316L,57317L,57318L,57319L,57320L,57321L,57322L,
8556157323L,57324L,57325L,57326L,57327L,57328L,57329L,57330L,57331L,57332L,
8556257333L,57334L,57335L,57336L,57337L,57338L,57339L,57340L,57341L,57342L,
8556357343L,57344L,57345L,57346L,57347L,57348L,57349L,57350L,57351L,57352L,
8556457353L,57354L,57355L,57356L,57357L,57358L,57359L,57360L,57361L,57362L,
8556557363L,57364L,57365L,57366L,57367L,57368L,57369L,57370L,57371L,57372L,
8556657373L,57374L,57375L,57376L,57377L,57378L,57379L,57380L,57381L,57382L,
8556757383L,57384L,57385L,57386L,57387L,57388L,57389L,57390L,57391L,57392L,
8556857393L,57394L,57395L,57396L,57397L,57398L,57399L,57400L,57401L,57402L,
8556957403L,57404L,57405L,57406L,57407L,57408L,57409L,57410L,57411L,57412L,
8557057413L,57414L,57415L,57416L,57417L,57418L,57419L,57420L,57421L,57422L,
8557157423L,57424L,57425L,57426L,57427L,57428L,57429L,57430L,57431L,57432L,
8557257433L,57434L,57435L,57436L,57437L,57438L,57439L,57440L,57441L,57442L,
8557357443L,57444L,57445L,57446L,57447L,57448L,57449L,57450L,57451L,57452L,
8557457453L,57454L,57455L,57456L,57457L,57458L,57459L,57460L,57461L,57462L,
8557557463L,57464L,57465L,57466L,57467L,57468L,57469L,57470L,57471L,57472L,
8557657473L,57474L,57475L,57476L,57477L,57478L,57479L,57480L,57481L,57482L,
8557757483L,57484L,57485L,57486L,57487L,57488L,57489L,57490L,57491L,57492L,
8557857493L,57494L,57495L,57496L,57497L,57498L,57499L,57500L,57501L,57502L,
8557957503L,57504L,57505L,57506L,57507L,57508L,57509L,57510L,57511L,57512L,
8558057513L,57514L,57515L,57516L,57517L,57518L,57519L,57520L,57521L,57522L,
8558157523L,57524L,57525L,57526L,57527L,57528L,57529L,57530L,57531L,57532L,
8558257533L,57534L,57535L,57536L,57537L,57538L,57539L,57540L,57541L,57542L,
8558357543L,57544L,57545L,57546L,57547L,57548L,57549L,57550L,57551L,57552L,
8558457553L,57554L,57555L,57556L,57557L,57558L,57559L,57560L,57561L,57562L,
8558557563L,57564L,57565L,57566L,57567L,57568L,57569L,57570L,57571L,57572L,
8558657573L,57574L,57575L,57576L,57577L,57578L,57579L,57580L,57581L,57582L,
8558757583L,57584L,57585L,57586L,57587L,57588L,57589L,57590L,57591L,57592L,
8558857593L,57594L,57595L,57596L,57597L,57598L,57599L,57600L,57601L,57602L,
8558957603L,57604L,57605L,57606L,57607L,57608L,57609L,57610L,57611L,57612L,
8559057613L,57614L,57615L,57616L,57617L,57618L,57619L,57620L,57621L,57622L,
8559157623L,57624L,57625L,57626L,57627L,57628L,57629L,57630L,57631L,57632L,
8559257633L,57634L,57635L,57636L,57637L,57638L,57639L,57640L,57641L,57642L,
8559357643L,57644L,57645L,57646L,57647L,57648L,57649L,57650L,57651L,57652L,
8559457653L,57654L,57655L,57656L,57657L,57658L,57659L,57660L,57661L,57662L,
8559557663L,57664L,57665L,57666L,57667L,57668L,57669L,57670L,57671L,57672L,
8559657673L,57674L,57675L,57676L,57677L,57678L,57679L,57680L,57681L,57682L,
8559757683L,57684L,57685L,57686L,57687L,57688L,57689L,57690L,57691L,57692L,
8559857693L,57694L,57695L,57696L,57697L,57698L,57699L,57700L,57701L,57702L,
8559957703L,57704L,57705L,57706L,57707L,57708L,57709L,57710L,57711L,57712L,
8560057713L,57714L,57715L,57716L,57717L,57718L,57719L,57720L,57721L,57722L,
8560157723L,57724L,57725L,57726L,57727L,57728L,57729L,57730L,57731L,57732L,
8560257733L,57734L,57735L,57736L,57737L,57738L,57739L,57740L,57741L,57742L,
8560357743L,57744L,57745L,57746L,57747L,57748L,57749L,57750L,57751L,57752L,
8560457753L,57754L,57755L,57756L,57757L,57758L,57759L,57760L,57761L,57762L,
8560557763L,57764L,57765L,57766L,57767L,57768L,57769L,57770L,57771L,57772L,
8560657773L,57774L,57775L,57776L,57777L,57778L,57779L,57780L,57781L,57782L,
8560757783L,57784L,57785L,57786L,57787L,57788L,57789L,57790L,57791L,57792L,
8560857793L,57794L,57795L,57796L,57797L,57798L,57799L,57800L,57801L,57802L,
8560957803L,57804L,57805L,57806L,57807L,57808L,57809L,57810L,57811L,57812L,
8561057813L,57814L,57815L,57816L,57817L,57818L,57819L,57820L,57821L,57822L,
8561157823L,57824L,57825L,57826L,57827L,57828L,57829L,57830L,57831L,57832L,
8561257833L,57834L,57835L,57836L,57837L,57838L,57839L,57840L,57841L,57842L,
8561357843L,57844L,57845L,57846L,57847L,57848L,57849L,57850L,57851L,57852L,
8561457853L,57854L,57855L,57856L,57857L,57858L,57859L,57860L,57861L,57862L,
8561557863L,57864L,57865L,57866L,57867L,57868L,57869L,57870L,57871L,57872L,
8561657873L,57874L,57875L,57876L,57877L,57878L,57879L,57880L,57881L,57882L,
8561757883L,57884L,57885L,57886L,57887L,57888L,57889L,57890L,57891L,57892L,
8561857893L,57894L,57895L,57896L,57897L,57898L,57899L,57900L,57901L,57902L,
8561957903L,57904L,57905L,57906L,57907L,57908L,57909L,57910L,57911L,57912L,
8562057913L,57914L,57915L,57916L,57917L,57918L,57919L,57920L,57921L,57922L,
8562157923L,57924L,57925L,57926L,57927L,57928L,57929L,57930L,57931L,57932L,
8562257933L,57934L,57935L,57936L,57937L,57938L,57939L,57940L,57941L,57942L,
8562357943L,57944L,57945L,57946L,57947L,57948L,57949L,57950L,57951L,57952L,
8562457953L,57954L,57955L,57956L,57957L,57958L,57959L,57960L,57961L,57962L,
8562557963L,57964L,57965L,57966L,57967L,57968L,57969L,57970L,57971L,57972L,
8562657973L,57974L,57975L,57976L,57977L,57978L,57979L,57980L,57981L,57982L,
8562757983L,57984L,57985L,57986L,57987L,57988L,57989L,57990L,57991L,57992L,
8562857993L,57994L,57995L,57996L,57997L,57998L,57999L,58000L,58001L,58002L,
8562958003L,58004L,58005L,58006L,58007L,58008L,58009L,58010L,58011L,58012L,
8563058013L,58014L,58015L,58016L,58017L,58018L,58019L,58020L,58021L,58022L,
8563158023L,58024L,58025L,58026L,58027L,58028L,58029L,58030L,58031L,58032L,
8563258033L,58034L,58035L,58036L,58037L,58038L,58039L,58040L,58041L,58042L,
8563358043L,58044L,58045L,58046L,58047L,58048L,58049L,58050L,58051L,58052L,
8563458053L,58054L,58055L,58056L,58057L,58058L,58059L,58060L,58061L,58062L,
8563558063L,58064L,58065L,58066L,58067L,58068L,58069L,58070L,58071L,58072L,
8563658073L,58074L,58075L,58076L,58077L,58078L,58079L,58080L,58081L,58082L,
8563758083L,58084L,58085L,58086L,58087L,58088L,58089L,58090L,58091L,58092L,
8563858093L,58094L,58095L,58096L,58097L,58098L,58099L,58100L,58101L,58102L,
8563958103L,58104L,58105L,58106L,58107L,58108L,58109L,58110L,58111L,58112L,
8564058113L,58114L,58115L,58116L,58117L,58118L,58119L,58120L,58121L,58122L,
8564158123L,58124L,58125L,58126L,58127L,58128L,58129L,58130L,58131L,58132L,
8564258133L,58134L,58135L,58136L,58137L,58138L,58139L,58140L,58141L,58142L,
8564358143L,58144L,58145L,58146L,58147L,58148L,58149L,58150L,58151L,58152L,
8564458153L,58154L,58155L,58156L,58157L,58158L,58159L,58160L,58161L,58162L,
8564558163L,58164L,58165L,58166L,58167L,58168L,58169L,58170L,58171L,58172L,
8564658173L,58174L,58175L,58176L,58177L,58178L,58179L,58180L,58181L,58182L,
8564758183L,58184L,58185L,58186L,58187L,58188L,58189L,58190L,58191L,58192L,
8564858193L,58194L,58195L,58196L,58197L,58198L,58199L,58200L,58201L,58202L,
8564958203L,58204L,58205L,58206L,58207L,58208L,58209L,58210L,58211L,58212L,
8565058213L,58214L,58215L,58216L,58217L,58218L,58219L,58220L,58221L,58222L,
8565158223L,58224L,58225L,58226L,58227L,58228L,58229L,58230L,58231L,58232L,
8565258233L,58234L,58235L,58236L,58237L,58238L,58239L,58240L,58241L,58242L,
8565358243L,58244L,58245L,58246L,58247L,58248L,58249L,58250L,58251L,58252L,
8565458253L,58254L,58255L,58256L,58257L,58258L,58259L,58260L,58261L,58262L,
8565558263L,58264L,58265L,58266L,58267L,58268L,58269L,58270L,58271L,58272L,
8565658273L,58274L,58275L,58276L,58277L,58278L,58279L,58280L,58281L,58282L,
8565758283L,58284L,58285L,58286L,58287L,58288L,58289L,58290L,58291L,58292L,
8565858293L,58294L,58295L,58296L,58297L,58298L,58299L,58300L,58301L,58302L,
8565958303L,58304L,58305L,58306L,58307L,58308L,58309L,58310L,58311L,58312L,
8566058313L,58314L,58315L,58316L,58317L,58318L,58319L,58320L,58321L,58322L,
8566158323L,58324L,58325L,58326L,58327L,58328L,58329L,58330L,58331L,58332L,
8566258333L,58334L,58335L,58336L,58337L,58338L,58339L,58340L,58341L,58342L,
8566358343L,58344L,58345L,58346L,58347L,58348L,58349L,58350L,58351L,58352L,
8566458353L,58354L,58355L,58356L,58357L,58358L,58359L,58360L,58361L,58362L,
8566558363L,58364L,58365L,58366L,58367L,58368L,58369L,58370L,58371L,58372L,
8566658373L,58374L,58375L,58376L,58377L,58378L,58379L,58380L,58381L,58382L,
8566758383L,58384L,58385L,58386L,58387L,58388L,58389L,58390L,58391L,58392L,
8566858393L,58394L,58395L,58396L,58397L,58398L,58399L,58400L,58401L,58402L,
8566958403L,58404L,58405L,58406L,58407L,58408L,58409L,58410L,58411L,58412L,
8567058413L,58414L,58415L,58416L,58417L,58418L,58419L,58420L,58421L,58422L,
8567158423L,58424L,58425L,58426L,58427L,58428L,58429L,58430L,58431L,58432L,
8567258433L,58434L,58435L,58436L,58437L,58438L,58439L,58440L,58441L,58442L,
8567358443L,58444L,58445L,58446L,58447L,58448L,58449L,58450L,58451L,58452L,
8567458453L,58454L,58455L,58456L,58457L,58458L,58459L,58460L,58461L,58462L,
8567558463L,58464L,58465L,58466L,58467L,58468L,58469L,58470L,58471L,58472L,
8567658473L,58474L,58475L,58476L,58477L,58478L,58479L,58480L,58481L,58482L,
8567758483L,58484L,58485L,58486L,58487L,58488L,58489L,58490L,58491L,58492L,
8567858493L,58494L,58495L,58496L,58497L,58498L,58499L,58500L,58501L,58502L,
8567958503L,58504L,58505L,58506L,58507L,58508L,58509L,58510L,58511L,58512L,
8568058513L,58514L,58515L,58516L,58517L,58518L,58519L,58520L,58521L,58522L,
8568158523L,58524L,58525L,58526L,58527L,58528L,58529L,58530L,58531L,58532L,
8568258533L,58534L,58535L,58536L,58537L,58538L,58539L,58540L,58541L,58542L,
8568358543L,58544L,58545L,58546L,58547L,58548L,58549L,58550L,58551L,58552L,
8568458553L,58554L,58555L,58556L,58557L,58558L,58559L,58560L,58561L,58562L,
8568558563L,58564L,58565L,58566L,58567L,58568L,58569L,58570L,58571L,58572L,
8568658573L,58574L,58575L,58576L,58577L,58578L,58579L,58580L,58581L,58582L,
8568758583L,58584L,58585L,58586L,58587L,58588L,58589L,58590L,58591L,58592L,
8568858593L,58594L,58595L,58596L,58597L,58598L,58599L,58600L,58601L,58602L,
8568958603L,58604L,58605L,58606L,58607L,58608L,58609L,58610L,58611L,58612L,
8569058613L,58614L,58615L,58616L,58617L,58618L,58619L,58620L,58621L,58622L,
8569158623L,58624L,58625L,58626L,58627L,58628L,58629L,58630L,58631L,58632L,
8569258633L,58634L,58635L,58636L,58637L,58638L,58639L,58640L,58641L,58642L,
8569358643L,58644L,58645L,58646L,58647L,58648L,58649L,58650L,58651L,58652L,
8569458653L,58654L,58655L,58656L,58657L,58658L,58659L,58660L,58661L,58662L,
8569558663L,58664L,58665L,58666L,58667L,58668L,58669L,58670L,58671L,58672L,
8569658673L,58674L,58675L,58676L,58677L,58678L,58679L,58680L,58681L,58682L,
8569758683L,58684L,58685L,58686L,58687L,58688L,58689L,58690L,58691L,58692L,
8569858693L,58694L,58695L,58696L,58697L,58698L,58699L,58700L,58701L,58702L,
8569958703L,58704L,58705L,58706L,58707L,58708L,58709L,58710L,58711L,58712L,
8570058713L,58714L,58715L,58716L,58717L,58718L,58719L,58720L,58721L,58722L,
8570158723L,58724L,58725L,58726L,58727L,58728L,58729L,58730L,58731L,58732L,
8570258733L,58734L,58735L,58736L,58737L,58738L,58739L,58740L,58741L,58742L,
8570358743L,58744L,58745L,58746L,58747L,58748L,58749L,58750L,58751L,58752L,
8570458753L,58754L,58755L,58756L,58757L,58758L,58759L,58760L,58761L,58762L,
8570558763L,58764L,58765L,58766L,58767L,58768L,58769L,58770L,58771L,58772L,
8570658773L,58774L,58775L,58776L,58777L,58778L,58779L,58780L,58781L,58782L,
8570758783L,58784L,58785L,58786L,58787L,58788L,58789L,58790L,58791L,58792L,
8570858793L,58794L,58795L,58796L,58797L,58798L,58799L,58800L,58801L,58802L,
8570958803L,58804L,58805L,58806L,58807L,58808L,58809L,58810L,58811L,58812L,
8571058813L,58814L,58815L,58816L,58817L,58818L,58819L,58820L,58821L,58822L,
8571158823L,58824L,58825L,58826L,58827L,58828L,58829L,58830L,58831L,58832L,
8571258833L,58834L,58835L,58836L,58837L,58838L,58839L,58840L,58841L,58842L,
8571358843L,58844L,58845L,58846L,58847L,58848L,58849L,58850L,58851L,58852L,
8571458853L,58854L,58855L,58856L,58857L,58858L,58859L,58860L,58861L,58862L,
8571558863L,58864L,58865L,58866L,58867L,58868L,58869L,58870L,58871L,58872L,
8571658873L,58874L,58875L,58876L,58877L,58878L,58879L,58880L,58881L,58882L,
8571758883L,58884L,58885L,58886L,58887L,58888L,58889L,58890L,58891L,58892L,
8571858893L,58894L,58895L,58896L,58897L,58898L,58899L,58900L,58901L,58902L,
8571958903L,58904L,58905L,58906L,58907L,58908L,58909L,58910L,58911L,58912L,
8572058913L,58914L,58915L,58916L,58917L,58918L,58919L,58920L,58921L,58922L,
8572158923L,58924L,58925L,58926L,58927L,58928L,58929L,58930L,58931L,58932L,
8572258933L,58934L,58935L,58936L,58937L,58938L,58939L,58940L,58941L,58942L,
8572358943L,58944L,58945L,58946L,58947L,58948L,58949L,58950L,58951L,58952L,
8572458953L,58954L,58955L,58956L,58957L,58958L,58959L,58960L,58961L,58962L,
8572558963L,58964L,58965L,58966L,58967L,58968L,58969L,58970L,58971L,58972L,
8572658973L,58974L,58975L,58976L,58977L,58978L,58979L,58980L,58981L,58982L,
8572758983L,58984L,58985L,58986L,58987L,58988L,58989L,58990L,58991L,58992L,
8572858993L,58994L,58995L,58996L,58997L,58998L,58999L,59000L,59001L,59002L,
8572959003L,59004L,59005L,59006L,59007L,59008L,59009L,59010L,59011L,59012L,
8573059013L,59014L,59015L,59016L,59017L,59018L,59019L,59020L,59021L,59022L,
8573159023L,59024L,59025L,59026L,59027L,59028L,59029L,59030L,59031L,59032L,
8573259033L,59034L,59035L,59036L,59037L,59038L,59039L,59040L,59041L,59042L,
8573359043L,59044L,59045L,59046L,59047L,59048L,59049L,59050L,59051L,59052L,
8573459053L,59054L,59055L,59056L,59057L,59058L,59059L,59060L,59061L,59062L,
8573559063L,59064L,59065L,59066L,59067L,59068L,59069L,59070L,59071L,59072L,
8573659073L,59074L,59075L,59076L,59077L,59078L,59079L,59080L,59081L,59082L,
8573759083L,59084L,59085L,59086L,59087L,59088L,59089L,59090L,59091L,59092L,
8573859093L,59094L,59095L,59096L,59097L,59098L,59099L,59100L,59101L,59102L,
8573959103L,59104L,59105L,59106L,59107L,59108L,59109L,59110L,59111L,59112L,
8574059113L,59114L,59115L,59116L,59117L,59118L,59119L,59120L,59121L,59122L,
8574159123L,59124L,59125L,59126L,59127L,59128L,59129L,59130L,59131L,59132L,
8574259133L,59134L,59135L,59136L,59137L,59138L,59139L,59140L,59141L,59142L,
8574359143L,59144L,59145L,59146L,59147L,59148L,59149L,59150L,59151L,59152L,
8574459153L,59154L,59155L,59156L,59157L,59158L,59159L,59160L,59161L,59162L,
8574559163L,59164L,59165L,59166L,59167L,59168L,59169L,59170L,59171L,59172L,
8574659173L,59174L,59175L,59176L,59177L,59178L,59179L,59180L,59181L,59182L,
8574759183L,59184L,59185L,59186L,59187L,59188L,59189L,59190L,59191L,59192L,
8574859193L,59194L,59195L,59196L,59197L,59198L,59199L,59200L,59201L,59202L,
8574959203L,59204L,59205L,59206L,59207L,59208L,59209L,59210L,59211L,59212L,
8575059213L,59214L,59215L,59216L,59217L,59218L,59219L,59220L,59221L,59222L,
8575159223L,59224L,59225L,59226L,59227L,59228L,59229L,59230L,59231L,59232L,
8575259233L,59234L,59235L,59236L,59237L,59238L,59239L,59240L,59241L,59242L,
8575359243L,59244L,59245L,59246L,59247L,59248L,59249L,59250L,59251L,59252L,
8575459253L,59254L,59255L,59256L,59257L,59258L,59259L,59260L,59261L,59262L,
8575559263L,59264L,59265L,59266L,59267L,59268L,59269L,59270L,59271L,59272L,
8575659273L,59274L,59275L,59276L,59277L,59278L,59279L,59280L,59281L,59282L,
8575759283L,59284L,59285L,59286L,59287L,59288L,59289L,59290L,59291L,59292L,
8575859293L,59294L,59295L,59296L,59297L,59298L,59299L,59300L,59301L,59302L,
8575959303L,59304L,59305L,59306L,59307L,59308L,59309L,59310L,59311L,59312L,
8576059313L,59314L,59315L,59316L,59317L,59318L,59319L,59320L,59321L,59322L,
8576159323L,59324L,59325L,59326L,59327L,59328L,59329L,59330L,59331L,59332L,
8576259333L,59334L,59335L,59336L,59337L,59338L,59339L,59340L,59341L,59342L,
8576359343L,59344L,59345L,59346L,59347L,59348L,59349L,59350L,59351L,59352L,
8576459353L,59354L,59355L,59356L,59357L,59358L,59359L,59360L,59361L,59362L,
8576559363L,59364L,59365L,59366L,59367L,59368L,59369L,59370L,59371L,59372L,
8576659373L,59374L,59375L,59376L,59377L,59378L,59379L,59380L,59381L,59382L,
8576759383L,59384L,59385L,59386L,59387L,59388L,59389L,59390L,59391L,59392L,
8576859393L,59394L,59395L,59396L,59397L,59398L,59399L,59400L,59401L,59402L,
8576959403L,59404L,59405L,59406L,59407L,59408L,59409L,59410L,59411L,59412L,
8577059413L,59414L,59415L,59416L,59417L,59418L,59419L,59420L,59421L,59422L,
8577159423L,59424L,59425L,59426L,59427L,59428L,59429L,59430L,59431L,59432L,
8577259433L,59434L,59435L,59436L,59437L,59438L,59439L,59440L,59441L,59442L,
8577359443L,59444L,59445L,59446L,59447L,59448L,59449L,59450L,59451L,59452L,
8577459453L,59454L,59455L,59456L,59457L,59458L,59459L,59460L,59461L,59462L,
8577559463L,59464L,59465L,59466L,59467L,59468L,59469L,59470L,59471L,59472L,
8577659473L,59474L,59475L,59476L,59477L,59478L,59479L,59480L,59481L,59482L,
8577759483L,59484L,59485L,59486L,59487L,59488L,59489L,59490L,59491L,59492L,
8577859493L,59494L,59495L,59496L,59497L,59498L,59499L,59500L,59501L,59502L,
8577959503L,59504L,59505L,59506L,59507L,59508L,59509L,59510L,59511L,59512L,
8578059513L,59514L,59515L,59516L,59517L,59518L,59519L,59520L,59521L,59522L,
8578159523L,59524L,59525L,59526L,59527L,59528L,59529L,59530L,59531L,59532L,
8578259533L,59534L,59535L,59536L,59537L,59538L,59539L,59540L,59541L,59542L,
8578359543L,59544L,59545L,59546L,59547L,59548L,59549L,59550L,59551L,59552L,
8578459553L,59554L,59555L,59556L,59557L,59558L,59559L,59560L,59561L,59562L,
8578559563L,59564L,59565L,59566L,59567L,59568L,59569L,59570L,59571L,59572L,
8578659573L,59574L,59575L,59576L,59577L,59578L,59579L,59580L,59581L,59582L,
8578759583L,59584L,59585L,59586L,59587L,59588L,59589L,59590L,59591L,59592L,
8578859593L,59594L,59595L,59596L,59597L,59598L,59599L,59600L,59601L,59602L,
8578959603L,59604L,59605L,59606L,59607L,59608L,59609L,59610L,59611L,59612L,
8579059613L,59614L,59615L,59616L,59617L,59618L,59619L,59620L,59621L,59622L,
8579159623L,59624L,59625L,59626L,59627L,59628L,59629L,59630L,59631L,59632L,
8579259633L,59634L,59635L,59636L,59637L,59638L,59639L,59640L,59641L,59642L,
8579359643L,59644L,59645L,59646L,59647L,59648L,59649L,59650L,59651L,59652L,
8579459653L,59654L,59655L,59656L,59657L,59658L,59659L,59660L,59661L,59662L,
8579559663L,59664L,59665L,59666L,59667L,59668L,59669L,59670L,59671L,59672L,
8579659673L,59674L,59675L,59676L,59677L,59678L,59679L,59680L,59681L,59682L,
8579759683L,59684L,59685L,59686L,59687L,59688L,59689L,59690L,59691L,59692L,
8579859693L,59694L,59695L,59696L,59697L,59698L,59699L,59700L,59701L,59702L,
8579959703L,59704L,59705L,59706L,59707L,59708L,59709L,59710L,59711L,59712L,
8580059713L,59714L,59715L,59716L,59717L,59718L,59719L,59720L,59721L,59722L,
8580159723L,59724L,59725L,59726L,59727L,59728L,59729L,59730L,59731L,59732L,
8580259733L,59734L,59735L,59736L,59737L,59738L,59739L,59740L,59741L,59742L,
8580359743L,59744L,59745L,59746L,59747L,59748L,59749L,59750L,59751L,59752L,
8580459753L,59754L,59755L,59756L,59757L,59758L,59759L,59760L,59761L,59762L,
8580559763L,59764L,59765L,59766L,59767L,59768L,59769L,59770L,59771L,59772L,
8580659773L,59774L,59775L,59776L,59777L,59778L,59779L,59780L,59781L,59782L,
8580759783L,59784L,59785L,59786L,59787L,59788L,59789L,59790L,59791L,59792L,
8580859793L,59794L,59795L,59796L,59797L,59798L,59799L,59800L,59801L,59802L,
8580959803L,59804L,59805L,59806L,59807L,59808L,59809L,59810L,59811L,59812L,
8581059813L,59814L,59815L,59816L,59817L,59818L,59819L,59820L,59821L,59822L,
8581159823L,59824L,59825L,59826L,59827L,59828L,59829L,59830L,59831L,59832L,
8581259833L,59834L,59835L,59836L,59837L,59838L,59839L,59840L,59841L,59842L,
8581359843L,59844L,59845L,59846L,59847L,59848L,59849L,59850L,59851L,59852L,
8581459853L,59854L,59855L,59856L,59857L,59858L,59859L,59860L,59861L,59862L,
8581559863L,59864L,59865L,59866L,59867L,59868L,59869L,59870L,59871L,59872L,
8581659873L,59874L,59875L,59876L,59877L,59878L,59879L,59880L,59881L,59882L,
8581759883L,59884L,59885L,59886L,59887L,59888L,59889L,59890L,59891L,59892L,
8581859893L,59894L,59895L,59896L,59897L,59898L,59899L,59900L,59901L,59902L,
8581959903L,59904L,59905L,59906L,59907L,59908L,59909L,59910L,59911L,59912L,
8582059913L,59914L,59915L,59916L,59917L,59918L,59919L,59920L,59921L,59922L,
8582159923L,59924L,59925L,59926L,59927L,59928L,59929L,59930L,59931L,59932L,
8582259933L,59934L,59935L,59936L,59937L,59938L,59939L,59940L,59941L,59942L,
8582359943L,59944L,59945L,59946L,59947L,59948L,59949L,59950L,59951L,59952L,
8582459953L,59954L,59955L,59956L,59957L,59958L,59959L,59960L,59961L,59962L,
8582559963L,59964L,59965L,59966L,59967L,59968L,59969L,59970L,59971L,59972L,
8582659973L,59974L,59975L,59976L,59977L,59978L,59979L,59980L,59981L,59982L,
8582759983L,59984L,59985L,59986L,59987L,59988L,59989L,59990L,59991L,59992L,
8582859993L,59994L,59995L,59996L,59997L,59998L,59999L,60000L,60001L,60002L,
8582960003L,60004L,60005L,60006L,60007L,60008L,60009L,60010L,60011L,60012L,
8583060013L,60014L,60015L,60016L,60017L,60018L,60019L,60020L,60021L,60022L,
8583160023L,60024L,60025L,60026L,60027L,60028L,60029L,60030L,60031L,60032L,
8583260033L,60034L,60035L,60036L,60037L,60038L,60039L,60040L,60041L,60042L,
8583360043L,60044L,60045L,60046L,60047L,60048L,60049L,60050L,60051L,60052L,
8583460053L,60054L,60055L,60056L,60057L,60058L,60059L,60060L,60061L,60062L,
8583560063L,60064L,60065L,60066L,60067L,60068L,60069L,60070L,60071L,60072L,
8583660073L,60074L,60075L,60076L,60077L,60078L,60079L,60080L,60081L,60082L,
8583760083L,60084L,60085L,60086L,60087L,60088L,60089L,60090L,60091L,60092L,
8583860093L,60094L,60095L,60096L,60097L,60098L,60099L,60100L,60101L,60102L,
8583960103L,60104L,60105L,60106L,60107L,60108L,60109L,60110L,60111L,60112L,
8584060113L,60114L,60115L,60116L,60117L,60118L,60119L,60120L,60121L,60122L,
8584160123L,60124L,60125L,60126L,60127L,60128L,60129L,60130L,60131L,60132L,
8584260133L,60134L,60135L,60136L,60137L,60138L,60139L,60140L,60141L,60142L,
8584360143L,60144L,60145L,60146L,60147L,60148L,60149L,60150L,60151L,60152L,
8584460153L,60154L,60155L,60156L,60157L,60158L,60159L,60160L,60161L,60162L,
8584560163L,60164L,60165L,60166L,60167L,60168L,60169L,60170L,60171L,60172L,
8584660173L,60174L,60175L,60176L,60177L,60178L,60179L,60180L,60181L,60182L,
8584760183L,60184L,60185L,60186L,60187L,60188L,60189L,60190L,60191L,60192L,
8584860193L,60194L,60195L,60196L,60197L,60198L,60199L,60200L,60201L,60202L,
8584960203L,60204L,60205L,60206L,60207L,60208L,60209L,60210L,60211L,60212L,
8585060213L,60214L,60215L,60216L,60217L,60218L,60219L,60220L,60221L,60222L,
8585160223L,60224L,60225L,60226L,60227L,60228L,60229L,60230L,60231L,60232L,
8585260233L,60234L,60235L,60236L,60237L,60238L,60239L,60240L,60241L,60242L,
8585360243L,60244L,60245L,60246L,60247L,60248L,60249L,60250L,60251L,60252L,
8585460253L,60254L,60255L,60256L,60257L,60258L,60259L,60260L,60261L,60262L,
8585560263L,60264L,60265L,60266L,60267L,60268L,60269L,60270L,60271L,60272L,
8585660273L,60274L,60275L,60276L,60277L,60278L,60279L,60280L,60281L,60282L,
8585760283L,60284L,60285L,60286L,60287L,60288L,60289L,60290L,60291L,60292L,
8585860293L,60294L,60295L,60296L,60297L,60298L,60299L,60300L,60301L,60302L,
8585960303L,60304L,60305L,60306L,60307L,60308L,60309L,60310L,60311L,60312L,
8586060313L,60314L,60315L,60316L,60317L,60318L,60319L,60320L,60321L,60322L,
8586160323L,60324L,60325L,60326L,60327L,60328L,60329L,60330L,60331L,60332L,
8586260333L,60334L,60335L,60336L,60337L,60338L,60339L,60340L,60341L,60342L,
8586360343L,60344L,60345L,60346L,60347L,60348L,60349L,60350L,60351L,60352L,
8586460353L,60354L,60355L,60356L,60357L,60358L,60359L,60360L,60361L,60362L,
8586560363L,60364L,60365L,60366L,60367L,60368L,60369L,60370L,60371L,60372L,
8586660373L,60374L,60375L,60376L,60377L,60378L,60379L,60380L,60381L,60382L,
8586760383L,60384L,60385L,60386L,60387L,60388L,60389L,60390L,60391L,60392L,
8586860393L,60394L,60395L,60396L,60397L,60398L,60399L,60400L,60401L,60402L,
8586960403L,60404L,60405L,60406L,60407L,60408L,60409L,60410L,60411L,60412L,
8587060413L,60414L,60415L,60416L,60417L,60418L,60419L,60420L,60421L,60422L,
8587160423L,60424L,60425L,60426L,60427L,60428L,60429L,60430L,60431L,60432L,
8587260433L,60434L,60435L,60436L,60437L,60438L,60439L,60440L,60441L,60442L,
8587360443L,60444L,60445L,60446L,60447L,60448L,60449L,60450L,60451L,60452L,
8587460453L,60454L,60455L,60456L,60457L,60458L,60459L,60460L,60461L,60462L,
8587560463L,60464L,60465L,60466L,60467L,60468L,60469L,60470L,60471L,60472L,
8587660473L,60474L,60475L,60476L,60477L,60478L,60479L,60480L,60481L,60482L,
8587760483L,60484L,60485L,60486L,60487L,60488L,60489L,60490L,60491L,60492L,
8587860493L,60494L,60495L,60496L,60497L,60498L,60499L,60500L,60501L,60502L,
8587960503L,60504L,60505L,60506L,60507L,60508L,60509L,60510L,60511L,60512L,
8588060513L,60514L,60515L,60516L,60517L,60518L,60519L,60520L,60521L,60522L,
8588160523L,60524L,60525L,60526L,60527L,60528L,60529L,60530L,60531L,60532L,
8588260533L,60534L,60535L,60536L,60537L,60538L,60539L,60540L,60541L,60542L,
8588360543L,60544L,60545L,60546L,60547L,60548L,60549L,60550L,60551L,60552L,
8588460553L,60554L,60555L,60556L,60557L,60558L,60559L,60560L,60561L,60562L,
8588560563L,60564L,60565L,60566L,60567L,60568L,60569L,60570L,60571L,60572L,
8588660573L,60574L,60575L,60576L,60577L,60578L,60579L,60580L,60581L,60582L,
8588760583L,60584L,60585L,60586L,60587L,60588L,60589L,60590L,60591L,60592L,
8588860593L,60594L,60595L,60596L,60597L,60598L,60599L,60600L,60601L,60602L,
8588960603L,60604L,60605L,60606L,60607L,60608L,60609L,60610L,60611L,60612L,
8589060613L,60614L,60615L,60616L,60617L,60618L,60619L,60620L,60621L,60622L,
8589160623L,60624L,60625L,60626L,60627L,60628L,60629L,60630L,60631L,60632L,
8589260633L,60634L,60635L,60636L,60637L,60638L,60639L,60640L,60641L,60642L,
8589360643L,60644L,60645L,60646L,60647L,60648L,60649L,60650L,60651L,60652L,
8589460653L,60654L,60655L,60656L,60657L,60658L,60659L,60660L,60661L,60662L,
8589560663L,60664L,60665L,60666L,60667L,60668L,60669L,60670L,60671L,60672L,
8589660673L,60674L,60675L,60676L,60677L,60678L,60679L,60680L,60681L,60682L,
8589760683L,60684L,60685L,60686L,60687L,60688L,60689L,60690L,60691L,60692L,
8589860693L,60694L,60695L,60696L,60697L,60698L,60699L,60700L,60701L,60702L,
8589960703L,60704L,60705L,60706L,60707L,60708L,60709L,60710L,60711L,60712L,
8590060713L,60714L,60715L,60716L,60717L,60718L,60719L,60720L,60721L,60722L,
8590160723L,60724L,60725L,60726L,60727L,60728L,60729L,60730L,60731L,60732L,
8590260733L,60734L,60735L,60736L,60737L,60738L,60739L,60740L,60741L,60742L,
8590360743L,60744L,60745L,60746L,60747L,60748L,60749L,60750L,60751L,60752L,
8590460753L,60754L,60755L,60756L,60757L,60758L,60759L,60760L,60761L,60762L,
8590560763L,60764L,60765L,60766L,60767L,60768L,60769L,60770L,60771L,60772L,
8590660773L,60774L,60775L,60776L,60777L,60778L,60779L,60780L,60781L,60782L,
8590760783L,60784L,60785L,60786L,60787L,60788L,60789L,60790L,60791L,60792L,
8590860793L,60794L,60795L,60796L,60797L,60798L,60799L,60800L,60801L,60802L,
8590960803L,60804L,60805L,60806L,60807L,60808L,60809L,60810L,60811L,60812L,
8591060813L,60814L,60815L,60816L,60817L,60818L,60819L,60820L,60821L,60822L,
8591160823L,60824L,60825L,60826L,60827L,60828L,60829L,60830L,60831L,60832L,
8591260833L,60834L,60835L,60836L,60837L,60838L,60839L,60840L,60841L,60842L,
8591360843L,60844L,60845L,60846L,60847L,60848L,60849L,60850L,60851L,60852L,
8591460853L,60854L,60855L,60856L,60857L,60858L,60859L,60860L,60861L,60862L,
8591560863L,60864L,60865L,60866L,60867L,60868L,60869L,60870L,60871L,60872L,
8591660873L,60874L,60875L,60876L,60877L,60878L,60879L,60880L,60881L,60882L,
8591760883L,60884L,60885L,60886L,60887L,60888L,60889L,60890L,60891L,60892L,
8591860893L,60894L,60895L,60896L,60897L,60898L,60899L,60900L,60901L,60902L,
8591960903L,60904L,60905L,60906L,60907L,60908L,60909L,60910L,60911L,60912L,
8592060913L,60914L,60915L,60916L,60917L,60918L,60919L,60920L,60921L,60922L,
8592160923L,60924L,60925L,60926L,60927L,60928L,60929L,60930L,60931L,60932L,
8592260933L,60934L,60935L,60936L,60937L,60938L,60939L,60940L,60941L,60942L,
8592360943L,60944L,60945L,60946L,60947L,60948L,60949L,60950L,60951L,60952L,
8592460953L,60954L,60955L,60956L,60957L,60958L,60959L,60960L,60961L,60962L,
8592560963L,60964L,60965L,60966L,60967L,60968L,60969L,60970L,60971L,60972L,
8592660973L,60974L,60975L,60976L,60977L,60978L,60979L,60980L,60981L,60982L,
8592760983L,60984L,60985L,60986L,60987L,60988L,60989L,60990L,60991L,60992L,
8592860993L,60994L,60995L,60996L,60997L,60998L,60999L,61000L,61001L,61002L,
8592961003L,61004L,61005L,61006L,61007L,61008L,61009L,61010L,61011L,61012L,
8593061013L,61014L,61015L,61016L,61017L,61018L,61019L,61020L,61021L,61022L,
8593161023L,61024L,61025L,61026L,61027L,61028L,61029L,61030L,61031L,61032L,
8593261033L,61034L,61035L,61036L,61037L,61038L,61039L,61040L,61041L,61042L,
8593361043L,61044L,61045L,61046L,61047L,61048L,61049L,61050L,61051L,61052L,
8593461053L,61054L,61055L,61056L,61057L,61058L,61059L,61060L,61061L,61062L,
8593561063L,61064L,61065L,61066L,61067L,61068L,61069L,61070L,61071L,61072L,
8593661073L,61074L,61075L,61076L,61077L,61078L,61079L,61080L,61081L,61082L,
8593761083L,61084L,61085L,61086L,61087L,61088L,61089L,61090L,61091L,61092L,
8593861093L,61094L,61095L,61096L,61097L,61098L,61099L,61100L,61101L,61102L,
8593961103L,61104L,61105L,61106L,61107L,61108L,61109L,61110L,61111L,61112L,
8594061113L,61114L,61115L,61116L,61117L,61118L,61119L,61120L,61121L,61122L,
8594161123L,61124L,61125L,61126L,61127L,61128L,61129L,61130L,61131L,61132L,
8594261133L,61134L,61135L,61136L,61137L,61138L,61139L,61140L,61141L,61142L,
8594361143L,61144L,61145L,61146L,61147L,61148L,61149L,61150L,61151L,61152L,
8594461153L,61154L,61155L,61156L,61157L,61158L,61159L,61160L,61161L,61162L,
8594561163L,61164L,61165L,61166L,61167L,61168L,61169L,61170L,61171L,61172L,
8594661173L,61174L,61175L,61176L,61177L,61178L,61179L,61180L,61181L,61182L,
8594761183L,61184L,61185L,61186L,61187L,61188L,61189L,61190L,61191L,61192L,
8594861193L,61194L,61195L,61196L,61197L,61198L,61199L,61200L,61201L,61202L,
8594961203L,61204L,61205L,61206L,61207L,61208L,61209L,61210L,61211L,61212L,
8595061213L,61214L,61215L,61216L,61217L,61218L,61219L,61220L,61221L,61222L,
8595161223L,61224L,61225L,61226L,61227L,61228L,61229L,61230L,61231L,61232L,
8595261233L,61234L,61235L,61236L,61237L,61238L,61239L,61240L,61241L,61242L,
8595361243L,61244L,61245L,61246L,61247L,61248L,61249L,61250L,61251L,61252L,
8595461253L,61254L,61255L,61256L,61257L,61258L,61259L,61260L,61261L,61262L,
8595561263L,61264L,61265L,61266L,61267L,61268L,61269L,61270L,61271L,61272L,
8595661273L,61274L,61275L,61276L,61277L,61278L,61279L,61280L,61281L,61282L,
8595761283L,61284L,61285L,61286L,61287L,61288L,61289L,61290L,61291L,61292L,
8595861293L,61294L,61295L,61296L,61297L,61298L,61299L,61300L,61301L,61302L,
8595961303L,61304L,61305L,61306L,61307L,61308L,61309L,61310L,61311L,61312L,
8596061313L,61314L,61315L,61316L,61317L,61318L,61319L,61320L,61321L,61322L,
8596161323L,61324L,61325L,61326L,61327L,61328L,61329L,61330L,61331L,61332L,
8596261333L,61334L,61335L,61336L,61337L,61338L,61339L,61340L,61341L,61342L,
8596361343L,61344L,61345L,61346L,61347L,61348L,61349L,61350L,61351L,61352L,
8596461353L,61354L,61355L,61356L,61357L,61358L,61359L,61360L,61361L,61362L,
8596561363L,61364L,61365L,61366L,61367L,61368L,61369L,61370L,61371L,61372L,
8596661373L,61374L,61375L,61376L,61377L,61378L,61379L,61380L,61381L,61382L,
8596761383L,61384L,61385L,61386L,61387L,61388L,61389L,61390L,61391L,61392L,
8596861393L,61394L,61395L,61396L,61397L,61398L,61399L,61400L,61401L,61402L,
8596961403L,61404L,61405L,61406L,61407L,61408L,61409L,61410L,61411L,61412L,
8597061413L,61414L,61415L,61416L,61417L,61418L,61419L,61420L,61421L,61422L,
8597161423L,61424L,61425L,61426L,61427L,61428L,61429L,61430L,61431L,61432L,
8597261433L,61434L,61435L,61436L,61437L,61438L,61439L,61440L,61441L,61442L,
8597361443L,61444L,61445L,61446L,61447L,61448L,61449L,61450L,61451L,61452L,
8597461453L,61454L,61455L,61456L,61457L,61458L,61459L,61460L,61461L,61462L,
8597561463L,61464L,61465L,61466L,61467L,61468L,61469L,61470L,61471L,61472L,
8597661473L,61474L,61475L,61476L,61477L,61478L,61479L,61480L,61481L,61482L,
8597761483L,61484L,61485L,61486L,61487L,61488L,61489L,61490L,61491L,61492L,
8597861493L,61494L,61495L,61496L,61497L,61498L,61499L,61500L,61501L,61502L,
8597961503L,61504L,61505L,61506L,61507L,61508L,61509L,61510L,61511L,61512L,
8598061513L,61514L,61515L,61516L,61517L,61518L,61519L,61520L,61521L,61522L,
8598161523L,61524L,61525L,61526L,61527L,61528L,61529L,61530L,61531L,61532L,
8598261533L,61534L,61535L,61536L,61537L,61538L,61539L,61540L,61541L,61542L,
8598361543L,61544L,61545L,61546L,61547L,61548L,61549L,61550L,61551L,61552L,
8598461553L,61554L,61555L,61556L,61557L,61558L,61559L,61560L,61561L,61562L,
8598561563L,61564L,61565L,61566L,61567L,61568L,61569L,61570L,61571L,61572L,
8598661573L,61574L,61575L,61576L,61577L,61578L,61579L,61580L,61581L,61582L,
8598761583L,61584L,61585L,61586L,61587L,61588L,61589L,61590L,61591L,61592L,
8598861593L,61594L,61595L,61596L,61597L,61598L,61599L,61600L,61601L,61602L,
8598961603L,61604L,61605L,61606L,61607L,61608L,61609L,61610L,61611L,61612L,
8599061613L,61614L,61615L,61616L,61617L,61618L,61619L,61620L,61621L,61622L,
8599161623L,61624L,61625L,61626L,61627L,61628L,61629L,61630L,61631L,61632L,
8599261633L,61634L,61635L,61636L,61637L,61638L,61639L,61640L,61641L,61642L,
8599361643L,61644L,61645L,61646L,61647L,61648L,61649L,61650L,61651L,61652L,
8599461653L,61654L,61655L,61656L,61657L,61658L,61659L,61660L,61661L,61662L,
8599561663L,61664L,61665L,61666L,61667L,61668L,61669L,61670L,61671L,61672L,
8599661673L,61674L,61675L,61676L,61677L,61678L,61679L,61680L,61681L,61682L,
8599761683L,61684L,61685L,61686L,61687L,61688L,61689L,61690L,61691L,61692L,
8599861693L,61694L,61695L,61696L,61697L,61698L,61699L,61700L,61701L,61702L,
8599961703L,61704L,61705L,61706L,61707L,61708L,61709L,61710L,61711L,61712L,
8600061713L,61714L,61715L,61716L,61717L,61718L,61719L,61720L,61721L,61722L,
8600161723L,61724L,61725L,61726L,61727L,61728L,61729L,61730L,61731L,61732L,
8600261733L,61734L,61735L,61736L,61737L,61738L,61739L,61740L,61741L,61742L,
8600361743L,61744L,61745L,61746L,61747L,61748L,61749L,61750L,61751L,61752L,
8600461753L,61754L,61755L,61756L,61757L,61758L,61759L,61760L,61761L,61762L,
8600561763L,61764L,61765L,61766L,61767L,61768L,61769L,61770L,61771L,61772L,
8600661773L,61774L,61775L,61776L,61777L,61778L,61779L,61780L,61781L,61782L,
8600761783L,61784L,61785L,61786L,61787L,61788L,61789L,61790L,61791L,61792L,
8600861793L,61794L,61795L,61796L,61797L,61798L,61799L,61800L,61801L,61802L,
8600961803L,61804L,61805L,61806L,61807L,61808L,61809L,61810L,61811L,61812L,
8601061813L,61814L,61815L,61816L,61817L,61818L,61819L,61820L,61821L,61822L,
8601161823L,61824L,61825L,61826L,61827L,61828L,61829L,61830L,61831L,61832L,
8601261833L,61834L,61835L,61836L,61837L,61838L,61839L,61840L,61841L,61842L,
8601361843L,61844L,61845L,61846L,61847L,61848L,61849L,61850L,61851L,61852L,
8601461853L,61854L,61855L,61856L,61857L,61858L,61859L,61860L,61861L,61862L,
8601561863L,61864L,61865L,61866L,61867L,61868L,61869L,61870L,61871L,61872L,
8601661873L,61874L,61875L,61876L,61877L,61878L,61879L,61880L,61881L,61882L,
8601761883L,61884L,61885L,61886L,61887L,61888L,61889L,61890L,61891L,61892L,
8601861893L,61894L,61895L,61896L,61897L,61898L,61899L,61900L,61901L,61902L,
8601961903L,61904L,61905L,61906L,61907L,61908L,61909L,61910L,61911L,61912L,
8602061913L,61914L,61915L,61916L,61917L,61918L,61919L,61920L,61921L,61922L,
8602161923L,61924L,61925L,61926L,61927L,61928L,61929L,61930L,61931L,61932L,
8602261933L,61934L,61935L,61936L,61937L,61938L,61939L,61940L,61941L,61942L,
8602361943L,61944L,61945L,61946L,61947L,61948L,61949L,61950L,61951L,61952L,
8602461953L,61954L,61955L,61956L,61957L,61958L,61959L,61960L,61961L,61962L,
8602561963L,61964L,61965L,61966L,61967L,61968L,61969L,61970L,61971L,61972L,
8602661973L,61974L,61975L,61976L,61977L,61978L,61979L,61980L,61981L,61982L,
8602761983L,61984L,61985L,61986L,61987L,61988L,61989L,61990L,61991L,61992L,
8602861993L,61994L,61995L,61996L,61997L,61998L,61999L,62000L,62001L,62002L,
8602962003L,62004L,62005L,62006L,62007L,62008L,62009L,62010L,62011L,62012L,
8603062013L,62014L,62015L,62016L,62017L,62018L,62019L,62020L,62021L,62022L,
8603162023L,62024L,62025L,62026L,62027L,62028L,62029L,62030L,62031L,62032L,
8603262033L,62034L,62035L,62036L,62037L,62038L,62039L,62040L,62041L,62042L,
8603362043L,62044L,62045L,62046L,62047L,62048L,62049L,62050L,62051L,62052L,
8603462053L,62054L,62055L,62056L,62057L,62058L,62059L,62060L,62061L,62062L,
8603562063L,62064L,62065L,62066L,62067L,62068L,62069L,62070L,62071L,62072L,
8603662073L,62074L,62075L,62076L,62077L,62078L,62079L,62080L,62081L,62082L,
8603762083L,62084L,62085L,62086L,62087L,62088L,62089L,62090L,62091L,62092L,
8603862093L,62094L,62095L,62096L,62097L,62098L,62099L,62100L,62101L,62102L,
8603962103L,62104L,62105L,62106L,62107L,62108L,62109L,62110L,62111L,62112L,
8604062113L,62114L,62115L,62116L,62117L,62118L,62119L,62120L,62121L,62122L,
8604162123L,62124L,62125L,62126L,62127L,62128L,62129L,62130L,62131L,62132L,
8604262133L,62134L,62135L,62136L,62137L,62138L,62139L,62140L,62141L,62142L,
8604362143L,62144L,62145L,62146L,62147L,62148L,62149L,62150L,62151L,62152L,
8604462153L,62154L,62155L,62156L,62157L,62158L,62159L,62160L,62161L,62162L,
8604562163L,62164L,62165L,62166L,62167L,62168L,62169L,62170L,62171L,62172L,
8604662173L,62174L,62175L,62176L,62177L,62178L,62179L,62180L,62181L,62182L,
8604762183L,62184L,62185L,62186L,62187L,62188L,62189L,62190L,62191L,62192L,
8604862193L,62194L,62195L,62196L,62197L,62198L,62199L,62200L,62201L,62202L,
8604962203L,62204L,62205L,62206L,62207L,62208L,62209L,62210L,62211L,62212L,
8605062213L,62214L,62215L,62216L,62217L,62218L,62219L,62220L,62221L,62222L,
8605162223L,62224L,62225L,62226L,62227L,62228L,62229L,62230L,62231L,62232L,
8605262233L,62234L,62235L,62236L,62237L,62238L,62239L,62240L,62241L,62242L,
8605362243L,62244L,62245L,62246L,62247L,62248L,62249L,62250L,62251L,62252L,
8605462253L,62254L,62255L,62256L,62257L,62258L,62259L,62260L,62261L,62262L,
8605562263L,62264L,62265L,62266L,62267L,62268L,62269L,62270L,62271L,62272L,
8605662273L,62274L,62275L,62276L,62277L,62278L,62279L,62280L,62281L,62282L,
8605762283L,62284L,62285L,62286L,62287L,62288L,62289L,62290L,62291L,62292L,
8605862293L,62294L,62295L,62296L,62297L,62298L,62299L,62300L,62301L,62302L,
8605962303L,62304L,62305L,62306L,62307L,62308L,62309L,62310L,62311L,62312L,
8606062313L,62314L,62315L,62316L,62317L,62318L,62319L,62320L,62321L,62322L,
8606162323L,62324L,62325L,62326L,62327L,62328L,62329L,62330L,62331L,62332L,
8606262333L,62334L,62335L,62336L,62337L,62338L,62339L,62340L,62341L,62342L,
8606362343L,62344L,62345L,62346L,62347L,62348L,62349L,62350L,62351L,62352L,
8606462353L,62354L,62355L,62356L,62357L,62358L,62359L,62360L,62361L,62362L,
8606562363L,62364L,62365L,62366L,62367L,62368L,62369L,62370L,62371L,62372L,
8606662373L,62374L,62375L,62376L,62377L,62378L,62379L,62380L,62381L,62382L,
8606762383L,62384L,62385L,62386L,62387L,62388L,62389L,62390L,62391L,62392L,
8606862393L,62394L,62395L,62396L,62397L,62398L,62399L,62400L,62401L,62402L,
8606962403L,62404L,62405L,62406L,62407L,62408L,62409L,62410L,62411L,62412L,
8607062413L,62414L,62415L,62416L,62417L,62418L,62419L,62420L,62421L,62422L,
8607162423L,62424L,62425L,62426L,62427L,62428L,62429L,62430L,62431L,62432L,
8607262433L,62434L,62435L,62436L,62437L,62438L,62439L,62440L,62441L,62442L,
8607362443L,62444L,62445L,62446L,62447L,62448L,62449L,62450L,62451L,62452L,
8607462453L,62454L,62455L,62456L,62457L,62458L,62459L,62460L,62461L,62462L,
8607562463L,62464L,62465L,62466L,62467L,62468L,62469L,62470L,62471L,62472L,
8607662473L,62474L,62475L,62476L,62477L,62478L,62479L,62480L,62481L,62482L,
8607762483L,62484L,62485L,62486L,62487L,62488L,62489L,62490L,62491L,62492L,
8607862493L,62494L,62495L,62496L,62497L,62498L,62499L,62500L,62501L,62502L,
8607962503L,62504L,62505L,62506L,62507L,62508L,62509L,62510L,62511L,62512L,
8608062513L,62514L,62515L,62516L,62517L,62518L,62519L,62520L,62521L,62522L,
8608162523L,62524L,62525L,62526L,62527L,62528L,62529L,62530L,62531L,62532L,
8608262533L,62534L,62535L,62536L,62537L,62538L,62539L,62540L,62541L,62542L,
8608362543L,62544L,62545L,62546L,62547L,62548L,62549L,62550L,62551L,62552L,
8608462553L,62554L,62555L,62556L,62557L,62558L,62559L,62560L,62561L,62562L,
8608562563L,62564L,62565L,62566L,62567L,62568L,62569L,62570L,62571L,62572L,
8608662573L,62574L,62575L,62576L,62577L,62578L,62579L,62580L,62581L,62582L,
8608762583L,62584L,62585L,62586L,62587L,62588L,62589L,62590L,62591L,62592L,
8608862593L,62594L,62595L,62596L,62597L,62598L,62599L,62600L,62601L,62602L,
8608962603L,62604L,62605L,62606L,62607L,62608L,62609L,62610L,62611L,62612L,
8609062613L,62614L,62615L,62616L,62617L,62618L,62619L,62620L,62621L,62622L,
8609162623L,62624L,62625L,62626L,62627L,62628L,62629L,62630L,62631L,62632L,
8609262633L,62634L,62635L,62636L,62637L,62638L,62639L,62640L,62641L,62642L,
8609362643L,62644L,62645L,62646L,62647L,62648L,62649L,62650L,62651L,62652L,
8609462653L,62654L,62655L,62656L,62657L,62658L,62659L,62660L,62661L,62662L,
8609562663L,62664L,62665L,62666L,62667L,62668L,62669L,62670L,62671L,62672L,
8609662673L,62674L,62675L,62676L,62677L,62678L,62679L,62680L,62681L,62682L,
8609762683L,62684L,62685L,62686L,62687L,62688L,62689L,62690L,62691L,62692L,
8609862693L,62694L,62695L,62696L,62697L,62698L,62699L,62700L,62701L,62702L,
8609962703L,62704L,62705L,62706L,62707L,62708L,62709L,62710L,62711L,62712L,
8610062713L,62714L,62715L,62716L,62717L,62718L,62719L,62720L,62721L,62722L,
8610162723L,62724L,62725L,62726L,62727L,62728L,62729L,62730L,62731L,62732L,
8610262733L,62734L,62735L,62736L,62737L,62738L,62739L,62740L,62741L,62742L,
8610362743L,62744L,62745L,62746L,62747L,62748L,62749L,62750L,62751L,62752L,
8610462753L,62754L,62755L,62756L,62757L,62758L,62759L,62760L,62761L,62762L,
8610562763L,62764L,62765L,62766L,62767L,62768L,62769L,62770L,62771L,62772L,
8610662773L,62774L,62775L,62776L,62777L,62778L,62779L,62780L,62781L,62782L,
8610762783L,62784L,62785L,62786L,62787L,62788L,62789L,62790L,62791L,62792L,
8610862793L,62794L,62795L,62796L,62797L,62798L,62799L,62800L,62801L,62802L,
8610962803L,62804L,62805L,62806L,62807L,62808L,62809L,62810L,62811L,62812L,
8611062813L,62814L,62815L,62816L,62817L,62818L,62819L,62820L,62821L,62822L,
8611162823L,62824L,62825L,62826L,62827L,62828L,62829L,62830L,62831L,62832L,
8611262833L,62834L,62835L,62836L,62837L,62838L,62839L,62840L,62841L,62842L,
8611362843L,62844L,62845L,62846L,62847L,62848L,62849L,62850L,62851L,62852L,
8611462853L,62854L,62855L,62856L,62857L,62858L,62859L,62860L,62861L,62862L,
8611562863L,62864L,62865L,62866L,62867L,62868L,62869L,62870L,62871L,62872L,
8611662873L,62874L,62875L,62876L,62877L,62878L,62879L,62880L,62881L,62882L,
8611762883L,62884L,62885L,62886L,62887L,62888L,62889L,62890L,62891L,62892L,
8611862893L,62894L,62895L,62896L,62897L,62898L,62899L,62900L,62901L,62902L,
8611962903L,62904L,62905L,62906L,62907L,62908L,62909L,62910L,62911L,62912L,
8612062913L,62914L,62915L,62916L,62917L,62918L,62919L,62920L,62921L,62922L,
8612162923L,62924L,62925L,62926L,62927L,62928L,62929L,62930L,62931L,62932L,
8612262933L,62934L,62935L,62936L,62937L,62938L,62939L,62940L,62941L,62942L,
8612362943L,62944L,62945L,62946L,62947L,62948L,62949L,62950L,62951L,62952L,
8612462953L,62954L,62955L,62956L,62957L,62958L,62959L,62960L,62961L,62962L,
8612562963L,62964L,62965L,62966L,62967L,62968L,62969L,62970L,62971L,62972L,
8612662973L,62974L,62975L,62976L,62977L,62978L,62979L,62980L,62981L,62982L,
8612762983L,62984L,62985L,62986L,62987L,62988L,62989L,62990L,62991L,62992L,
8612862993L,62994L,62995L,62996L,62997L,62998L,62999L,63000L,63001L,63002L,
8612963003L,63004L,63005L,63006L,63007L,63008L,63009L,63010L,63011L,63012L,
8613063013L,63014L,63015L,63016L,63017L,63018L,63019L,63020L,63021L,63022L,
8613163023L,63024L,63025L,63026L,63027L,63028L,63029L,63030L,63031L,63032L,
8613263033L,63034L,63035L,63036L,63037L,63038L,63039L,63040L,63041L,63042L,
8613363043L,63044L,63045L,63046L,63047L,63048L,63049L,63050L,63051L,63052L,
8613463053L,63054L,63055L,63056L,63057L,63058L,63059L,63060L,63061L,63062L,
8613563063L,63064L,63065L,63066L,63067L,63068L,63069L,63070L,63071L,63072L,
8613663073L,63074L,63075L,63076L,63077L,63078L,63079L,63080L,63081L,63082L,
8613763083L,63084L,63085L,63086L,63087L,63088L,63089L,63090L,63091L,63092L,
8613863093L,63094L,63095L,63096L,63097L,63098L,63099L,63100L,63101L,63102L,
8613963103L,63104L,63105L,63106L,63107L,63108L,63109L,63110L,63111L,63112L,
8614063113L,63114L,63115L,63116L,63117L,63118L,63119L,63120L,63121L,63122L,
8614163123L,63124L,63125L,63126L,63127L,63128L,63129L,63130L,63131L,63132L,
8614263133L,63134L,63135L,63136L,63137L,63138L,63139L,63140L,63141L,63142L,
8614363143L,63144L,63145L,63146L,63147L,63148L,63149L,63150L,63151L,63152L,
8614463153L,63154L,63155L,63156L,63157L,63158L,63159L,63160L,63161L,63162L,
8614563163L,63164L,63165L,63166L,63167L,63168L,63169L,63170L,63171L,63172L,
8614663173L,63174L,63175L,63176L,63177L,63178L,63179L,63180L,63181L,63182L,
8614763183L,63184L,63185L,63186L,63187L,63188L,63189L,63190L,63191L,63192L,
8614863193L,63194L,63195L,63196L,63197L,63198L,63199L,63200L,63201L,63202L,
8614963203L,63204L,63205L,63206L,63207L,63208L,63209L,63210L,63211L,63212L,
8615063213L,63214L,63215L,63216L,63217L,63218L,63219L,63220L,63221L,63222L,
8615163223L,63224L,63225L,63226L,63227L,63228L,63229L,63230L,63231L,63232L,
8615263233L,63234L,63235L,63236L,63237L,63238L,63239L,63240L,63241L,63242L,
8615363243L,63244L,63245L,63246L,63247L,63248L,63249L,63250L,63251L,63252L,
8615463253L,63254L,63255L,63256L,63257L,63258L,63259L,63260L,63261L,63262L,
8615563263L,63264L,63265L,63266L,63267L,63268L,63269L,63270L,63271L,63272L,
8615663273L,63274L,63275L,63276L,63277L,63278L,63279L,63280L,63281L,63282L,
8615763283L,63284L,63285L,63286L,63287L,63288L,63289L,63290L,63291L,63292L,
8615863293L,63294L,63295L,63296L,63297L,63298L,63299L,63300L,63301L,63302L,
8615963303L,63304L,63305L,63306L,63307L,63308L,63309L,63310L,63311L,63312L,
8616063313L,63314L,63315L,63316L,63317L,63318L,63319L,63320L,63321L,63322L,
8616163323L,63324L,63325L,63326L,63327L,63328L,63329L,63330L,63331L,63332L,
8616263333L,63334L,63335L,63336L,63337L,63338L,63339L,63340L,63341L,63342L,
8616363343L,63344L,63345L,63346L,63347L,63348L,63349L,63350L,63351L,63352L,
8616463353L,63354L,63355L,63356L,63357L,63358L,63359L,63360L,63361L,63362L,
8616563363L,63364L,63365L,63366L,63367L,63368L,63369L,63370L,63371L,63372L,
8616663373L,63374L,63375L,63376L,63377L,63378L,63379L,63380L,63381L,63382L,
8616763383L,63384L,63385L,63386L,63387L,63388L,63389L,63390L,63391L,63392L,
8616863393L,63394L,63395L,63396L,63397L,63398L,63399L,63400L,63401L,63402L,
8616963403L,63404L,63405L,63406L,63407L,63408L,63409L,63410L,63411L,63412L,
8617063413L,63414L,63415L,63416L,63417L,63418L,63419L,63420L,63421L,63422L,
8617163423L,63424L,63425L,63426L,63427L,63428L,63429L,63430L,63431L,63432L,
8617263433L,63434L,63435L,63436L,63437L,63438L,63439L,63440L,63441L,63442L,
8617363443L,63444L,63445L,63446L,63447L,63448L,63449L,63450L,63451L,63452L,
8617463453L,63454L,63455L,63456L,63457L,63458L,63459L,63460L,63461L,63462L,
8617563463L,63464L,63465L,63466L,63467L,63468L,63469L,63470L,63471L,63472L,
8617663473L,63474L,63475L,63476L,63477L,63478L,63479L,63480L,63481L,63482L,
8617763483L,63484L,63485L,63486L,63487L,63488L,63489L,63490L,63491L,63492L,
8617863493L,63494L,63495L,63496L,63497L,63498L,63499L,63500L,63501L,63502L,
8617963503L,63504L,63505L,63506L,63507L,63508L,63509L,63510L,63511L,63512L,
8618063513L,63514L,63515L,63516L,63517L,63518L,63519L,63520L,63521L,63522L,
8618163523L,63524L,63525L,63526L,63527L,63528L,63529L,63530L,63531L,63532L,
8618263533L,63534L,63535L,63536L,63537L,63538L,63539L,63540L,63541L,63542L,
8618363543L,63544L,63545L,63546L,63547L,63548L,63549L,63550L,63551L,63552L,
8618463553L,63554L,63555L,63556L,63557L,63558L,63559L,63560L,63561L,63562L,
8618563563L,63564L,63565L,63566L,63567L,63568L,63569L,63570L,63571L,63572L,
8618663573L,63574L,63575L,63576L,63577L,63578L,63579L,63580L,63581L,63582L,
8618763583L,63584L,63585L,63586L,63587L,63588L,63589L,63590L,63591L,63592L,
8618863593L,63594L,63595L,63596L,63597L,63598L,63599L,63600L,63601L,63602L,
8618963603L,63604L,63605L,63606L,63607L,63608L,63609L,63610L,63611L,63612L,
8619063613L,63614L,63615L,63616L,63617L,63618L,63619L,63620L,63621L,63622L,
8619163623L,63624L,63625L,63626L,63627L,63628L,63629L,63630L,63631L,63632L,
8619263633L,63634L,63635L,63636L,63637L,63638L,63639L,63640L,63641L,63642L,
8619363643L,63644L,63645L,63646L,63647L,63648L,63649L,63650L,63651L,63652L,
8619463653L,63654L,63655L,63656L,63657L,63658L,63659L,63660L,63661L,63662L,
8619563663L,63664L,63665L,63666L,63667L,63668L,63669L,63670L,63671L,63672L,
8619663673L,63674L,63675L,63676L,63677L,63678L,63679L,63680L,63681L,63682L,
8619763683L,63684L,63685L,63686L,63687L,63688L,63689L,63690L,63691L,63692L,
8619863693L,63694L,63695L,63696L,63697L,63698L,63699L,63700L,63701L,63702L,
8619963703L,63704L,63705L,63706L,63707L,63708L,63709L,63710L,63711L,63712L,
8620063713L,63714L,63715L,63716L,63717L,63718L,63719L,63720L,63721L,63722L,
8620163723L,63724L,63725L,63726L,63727L,63728L,63729L,63730L,63731L,63732L,
8620263733L,63734L,63735L,63736L,63737L,63738L,63739L,63740L,63741L,63742L,
8620363743L,63744L,63745L,63746L,63747L,63748L,63749L,63750L,63751L,63752L,
8620463753L,63754L,63755L,63756L,63757L,63758L,63759L,63760L,63761L,63762L,
8620563763L,63764L,63765L,63766L,63767L,63768L,63769L,63770L,63771L,63772L,
8620663773L,63774L,63775L,63776L,63777L,63778L,63779L,63780L,63781L,63782L,
8620763783L,63784L,63785L,63786L,63787L,63788L,63789L,63790L,63791L,63792L,
8620863793L,63794L,63795L,63796L,63797L,63798L,63799L,63800L,63801L,63802L,
8620963803L,63804L,63805L,63806L,63807L,63808L,63809L,63810L,63811L,63812L,
8621063813L,63814L,63815L,63816L,63817L,63818L,63819L,63820L,63821L,63822L,
8621163823L,63824L,63825L,63826L,63827L,63828L,63829L,63830L,63831L,63832L,
8621263833L,63834L,63835L,63836L,63837L,63838L,63839L,63840L,63841L,63842L,
8621363843L,63844L,63845L,63846L,63847L,63848L,63849L,63850L,63851L,63852L,
8621463853L,63854L,63855L,63856L,63857L,63858L,63859L,63860L,63861L,63862L,
8621563863L,63864L,63865L,63866L,63867L,63868L,63869L,63870L,63871L,63872L,
8621663873L,63874L,63875L,63876L,63877L,63878L,63879L,63880L,63881L,63882L,
8621763883L,63884L,63885L,63886L,63887L,63888L,63889L,63890L,63891L,63892L,
8621863893L,63894L,63895L,63896L,63897L,63898L,63899L,63900L,63901L,63902L,
8621963903L,63904L,63905L,63906L,63907L,63908L,63909L,63910L,63911L,63912L,
8622063913L,63914L,63915L,63916L,63917L,63918L,63919L,63920L,63921L,63922L,
8622163923L,63924L,63925L,63926L,63927L,63928L,63929L,63930L,63931L,63932L,
8622263933L,63934L,63935L,63936L,63937L,63938L,63939L,63940L,63941L,63942L,
8622363943L,63944L,63945L,63946L,63947L,63948L,63949L,63950L,63951L,63952L,
8622463953L,63954L,63955L,63956L,63957L,63958L,63959L,63960L,63961L,63962L,
8622563963L,63964L,63965L,63966L,63967L,63968L,63969L,63970L,63971L,63972L,
8622663973L,63974L,63975L,63976L,63977L,63978L,63979L,63980L,63981L,63982L,
8622763983L,63984L,63985L,63986L,63987L,63988L,63989L,63990L,63991L,63992L,
8622863993L,63994L,63995L,63996L,63997L,63998L,63999L,64000L,64001L,64002L,
8622964003L,64004L,64005L,64006L,64007L,64008L,64009L,64010L,64011L,64012L,
8623064013L,64014L,64015L,64016L,64017L,64018L,64019L,64020L,64021L,64022L,
8623164023L,64024L,64025L,64026L,64027L,64028L,64029L,64030L,64031L,64032L,
8623264033L,64034L,64035L,64036L,64037L,64038L,64039L,64040L,64041L,64042L,
8623364043L,64044L,64045L,64046L,64047L,64048L,64049L,64050L,64051L,64052L,
8623464053L,64054L,64055L,64056L,64057L,64058L,64059L,64060L,64061L,64062L,
8623564063L,64064L,64065L,64066L,64067L,64068L,64069L,64070L,64071L,64072L,
8623664073L,64074L,64075L,64076L,64077L,64078L,64079L,64080L,64081L,64082L,
8623764083L,64084L,64085L,64086L,64087L,64088L,64089L,64090L,64091L,64092L,
8623864093L,64094L,64095L,64096L,64097L,64098L,64099L,64100L,64101L,64102L,
8623964103L,64104L,64105L,64106L,64107L,64108L,64109L,64110L,64111L,64112L,
8624064113L,64114L,64115L,64116L,64117L,64118L,64119L,64120L,64121L,64122L,
8624164123L,64124L,64125L,64126L,64127L,64128L,64129L,64130L,64131L,64132L,
8624264133L,64134L,64135L,64136L,64137L,64138L,64139L,64140L,64141L,64142L,
8624364143L,64144L,64145L,64146L,64147L,64148L,64149L,64150L,64151L,64152L,
8624464153L,64154L,64155L,64156L,64157L,64158L,64159L,64160L,64161L,64162L,
8624564163L,64164L,64165L,64166L,64167L,64168L,64169L,64170L,64171L,64172L,
8624664173L,64174L,64175L,64176L,64177L,64178L,64179L,64180L,64181L,64182L,
8624764183L,64184L,64185L,64186L,64187L,64188L,64189L,64190L,64191L,64192L,
8624864193L,64194L,64195L,64196L,64197L,64198L,64199L,64200L,64201L,64202L,
8624964203L,64204L,64205L,64206L,64207L,64208L,64209L,64210L,64211L,64212L,
8625064213L,64214L,64215L,64216L,64217L,64218L,64219L,64220L,64221L,64222L,
8625164223L,64224L,64225L,64226L,64227L,64228L,64229L,64230L,64231L,64232L,
8625264233L,64234L,64235L,64236L,64237L,64238L,64239L,64240L,64241L,64242L,
8625364243L,64244L,64245L,64246L,64247L,64248L,64249L,64250L,64251L,64252L,
8625464253L,64254L,64255L,64256L,64257L,64258L,64259L,64260L,64261L,64262L,
8625564263L,64264L,64265L,64266L,64267L,64268L,64269L,64270L,64271L,64272L,
8625664273L,64274L,64275L,64276L,64277L,64278L,64279L,64280L,64281L,64282L,
8625764283L,64284L,64285L,64286L,64287L,64288L,64289L,64290L,64291L,64292L,
8625864293L,64294L,64295L,64296L,64297L,64298L,64299L,64300L,64301L,64302L,
8625964303L,64304L,64305L,64306L,64307L,64308L,64309L,64310L,64311L,64312L,
8626064313L,64314L,64315L,64316L,64317L,64318L,64319L,64320L,64321L,64322L,
8626164323L,64324L,64325L,64326L,64327L,64328L,64329L,64330L,64331L,64332L,
8626264333L,64334L,64335L,64336L,64337L,64338L,64339L,64340L,64341L,64342L,
8626364343L,64344L,64345L,64346L,64347L,64348L,64349L,64350L,64351L,64352L,
8626464353L,64354L,64355L,64356L,64357L,64358L,64359L,64360L,64361L,64362L,
8626564363L,64364L,64365L,64366L,64367L,64368L,64369L,64370L,64371L,64372L,
8626664373L,64374L,64375L,64376L,64377L,64378L,64379L,64380L,64381L,64382L,
8626764383L,64384L,64385L,64386L,64387L,64388L,64389L,64390L,64391L,64392L,
8626864393L,64394L,64395L,64396L,64397L,64398L,64399L,64400L,64401L,64402L,
8626964403L,64404L,64405L,64406L,64407L,64408L,64409L,64410L,64411L,64412L,
8627064413L,64414L,64415L,64416L,64417L,64418L,64419L,64420L,64421L,64422L,
8627164423L,64424L,64425L,64426L,64427L,64428L,64429L,64430L,64431L,64432L,
8627264433L,64434L,64435L,64436L,64437L,64438L,64439L,64440L,64441L,64442L,
8627364443L,64444L,64445L,64446L,64447L,64448L,64449L,64450L,64451L,64452L,
8627464453L,64454L,64455L,64456L,64457L,64458L,64459L,64460L,64461L,64462L,
8627564463L,64464L,64465L,64466L,64467L,64468L,64469L,64470L,64471L,64472L,
8627664473L,64474L,64475L,64476L,64477L,64478L,64479L,64480L,64481L,64482L,
8627764483L,64484L,64485L,64486L,64487L,64488L,64489L,64490L,64491L,64492L,
8627864493L,64494L,64495L,64496L,64497L,64498L,64499L,64500L,64501L,64502L,
8627964503L,64504L,64505L,64506L,64507L,64508L,64509L,64510L,64511L,64512L,
8628064513L,64514L,64515L,64516L,64517L,64518L,64519L,64520L,64521L,64522L,
8628164523L,64524L,64525L,64526L,64527L,64528L,64529L,64530L,64531L,64532L,
8628264533L,64534L,64535L,64536L,64537L,64538L,64539L,64540L,64541L,64542L,
8628364543L,64544L,64545L,64546L,64547L,64548L,64549L,64550L,64551L,64552L,
8628464553L,64554L,64555L,64556L,64557L,64558L,64559L,64560L,64561L,64562L,
8628564563L,64564L,64565L,64566L,64567L,64568L,64569L,64570L,64571L,64572L,
8628664573L,64574L,64575L,64576L,64577L,64578L,64579L,64580L,64581L,64582L,
8628764583L,64584L,64585L,64586L,64587L,64588L,64589L,64590L,64591L,64592L,
8628864593L,64594L,64595L,64596L,64597L,64598L,64599L,64600L,64601L,64602L,
8628964603L,64604L,64605L,64606L,64607L,64608L,64609L,64610L,64611L,64612L,
8629064613L,64614L,64615L,64616L,64617L,64618L,64619L,64620L,64621L,64622L,
8629164623L,64624L,64625L,64626L,64627L,64628L,64629L,64630L,64631L,64632L,
8629264633L,64634L,64635L,64636L,64637L,64638L,64639L,64640L,64641L,64642L,
8629364643L,64644L,64645L,64646L,64647L,64648L,64649L,64650L,64651L,64652L,
8629464653L,64654L,64655L,64656L,64657L,64658L,64659L,64660L,64661L,64662L,
8629564663L,64664L,64665L,64666L,64667L,64668L,64669L,64670L,64671L,64672L,
8629664673L,64674L,64675L,64676L,64677L,64678L,64679L,64680L,64681L,64682L,
8629764683L,64684L,64685L,64686L,64687L,64688L,64689L,64690L,64691L,64692L,
8629864693L,64694L,64695L,64696L,64697L,64698L,64699L,64700L,64701L,64702L,
8629964703L,64704L,64705L,64706L,64707L,64708L,64709L,64710L,64711L,64712L,
8630064713L,64714L,64715L,64716L,64717L,64718L,64719L,64720L,64721L,64722L,
8630164723L,64724L,64725L,64726L,64727L,64728L,64729L,64730L,64731L,64732L,
8630264733L,64734L,64735L,64736L,64737L,64738L,64739L,64740L,64741L,64742L,
8630364743L,64744L,64745L,64746L,64747L,64748L,64749L,64750L,64751L,64752L,
8630464753L,64754L,64755L,64756L,64757L,64758L,64759L,64760L,64761L,64762L,
8630564763L,64764L,64765L,64766L,64767L,64768L,64769L,64770L,64771L,64772L,
8630664773L,64774L,64775L,64776L,64777L,64778L,64779L,64780L,64781L,64782L,
8630764783L,64784L,64785L,64786L,64787L,64788L,64789L,64790L,64791L,64792L,
8630864793L,64794L,64795L,64796L,64797L,64798L,64799L,64800L,64801L,64802L,
8630964803L,64804L,64805L,64806L,64807L,64808L,64809L,64810L,64811L,64812L,
8631064813L,64814L,64815L,64816L,64817L,64818L,64819L,64820L,64821L,64822L,
8631164823L,64824L,64825L,64826L,64827L,64828L,64829L,64830L,64831L,64832L,
8631264833L,64834L,64835L,64836L,64837L,64838L,64839L,64840L,64841L,64842L,
8631364843L,64844L,64845L,64846L,64847L,64848L,64849L,64850L,64851L,64852L,
8631464853L,64854L,64855L,64856L,64857L,64858L,64859L,64860L,64861L,64862L,
8631564863L,64864L,64865L,64866L,64867L,64868L,64869L,64870L,64871L,64872L,
8631664873L,64874L,64875L,64876L,64877L,64878L,64879L,64880L,64881L,64882L,
8631764883L,64884L,64885L,64886L,64887L,64888L,64889L,64890L,64891L,64892L,
8631864893L,64894L,64895L,64896L,64897L,64898L,64899L,64900L,64901L,64902L,
8631964903L,64904L,64905L,64906L,64907L,64908L,64909L,64910L,64911L,64912L,
8632064913L,64914L,64915L,64916L,64917L,64918L,64919L,64920L,64921L,64922L,
8632164923L,64924L,64925L,64926L,64927L,64928L,64929L,64930L,64931L,64932L,
8632264933L,64934L,64935L,64936L,64937L,64938L,64939L,64940L,64941L,64942L,
8632364943L,64944L,64945L,64946L,64947L,64948L,64949L,64950L,64951L,64952L,
8632464953L,64954L,64955L,64956L,64957L,64958L,64959L,64960L,64961L,64962L,
8632564963L,64964L,64965L,64966L,64967L,64968L,64969L,64970L,64971L,64972L,
8632664973L,64974L,64975L,64976L,64977L,64978L,64979L,64980L,64981L,64982L,
8632764983L,64984L,64985L,64986L,64987L,64988L,64989L,64990L,64991L,64992L,
8632864993L,64994L,64995L,64996L,64997L,64998L,64999L,65000L,65001L,65002L,
8632965003L,65004L,65005L,65006L,65007L,65008L,65009L,65010L,65011L,65012L,
8633065013L,65014L,65015L,65016L,65017L,65018L,65019L,65020L,65021L,65022L,
8633165023L,65024L,65025L,65026L,65027L,65028L,65029L,65030L,65031L,65032L,
8633265033L,65034L,65035L,65036L,65037L,65038L,65039L,65040L,65041L,65042L,
8633365043L,65044L,65045L,65046L,65047L,65048L,65049L,65050L,65051L,65052L,
8633465053L,65054L,65055L,65056L,65057L,65058L,65059L,65060L,65061L,65062L,
8633565063L,65064L,65065L,65066L,65067L,65068L,65069L,65070L,65071L,65072L,
8633665073L,65074L,65075L,65076L,65077L,65078L,65079L,65080L,65081L,65082L,
8633765083L,65084L,65085L,65086L,65087L,65088L,65089L,65090L,65091L,65092L,
8633865093L,65094L,65095L,65096L,65097L,65098L,65099L,65100L,65101L,65102L,
8633965103L,65104L,65105L,65106L,65107L,65108L,65109L,65110L,65111L,65112L,
8634065113L,65114L,65115L,65116L,65117L,65118L,65119L,65120L,65121L,65122L,
8634165123L,65124L,65125L,65126L,65127L,65128L,65129L,65130L,65131L,65132L,
8634265133L,65134L,65135L,65136L,65137L,65138L,65139L,65140L,65141L,65142L,
8634365143L,65144L,65145L,65146L,65147L,65148L,65149L,65150L,65151L,65152L,
8634465153L,65154L,65155L,65156L,65157L,65158L,65159L,65160L,65161L,65162L,
8634565163L,65164L,65165L,65166L,65167L,65168L,65169L,65170L,65171L,65172L,
8634665173L,65174L,65175L,65176L,65177L,65178L,65179L,65180L,65181L,65182L,
8634765183L,65184L,65185L,65186L,65187L,65188L,65189L,65190L,65191L,65192L,
8634865193L,65194L,65195L,65196L,65197L,65198L,65199L,65200L,65201L,65202L,
8634965203L,65204L,65205L,65206L,65207L,65208L,65209L,65210L,65211L,65212L,
8635065213L,65214L,65215L,65216L,65217L,65218L,65219L,65220L,65221L,65222L,
8635165223L,65224L,65225L,65226L,65227L,65228L,65229L,65230L,65231L,65232L,
8635265233L,65234L,65235L,65236L,65237L,65238L,65239L,65240L,65241L,65242L,
8635365243L,65244L,65245L,65246L,65247L,65248L,65249L,65250L,65251L,65252L,
8635465253L,65254L,65255L,65256L,65257L,65258L,65259L,65260L,65261L,65262L,
8635565263L,65264L,65265L,65266L,65267L,65268L,65269L,65270L,65271L,65272L,
8635665273L,65274L,65275L,65276L,65277L,65278L,65279L,65280L,65281L,65282L,
8635765283L,65284L,65285L,65286L,65287L,65288L,65289L,65290L,65291L,65292L,
8635865293L,65294L,65295L,65296L,65297L,65298L,65299L,65300L,65301L,65302L,
8635965303L,65304L,65305L,65306L,65307L,65308L,65309L,65310L,65311L,65312L,
8636065313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L,
8636165323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L,
8636265333L,65334L,65335L,65336L,65337L,65338L,65339L,65340L,65341L,65342L,
8636365343L,65344L,65313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,
8636465321L,65322L,65323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,
8636565331L,65332L,65333L,65334L,65335L,65336L,65337L,65338L,65371L,65372L,
8636665373L,65374L,65375L,65376L,65377L,65378L,65379L,65380L,65381L,65382L,
8636765383L,65384L,65385L,65386L,65387L,65388L,65389L,65390L,65391L,65392L,
8636865393L,65394L,65395L,65396L,65397L,65398L,65399L,65400L,65401L,65402L,
8636965403L,65404L,65405L,65406L,65407L,65408L,65409L,65410L,65411L,65412L,
8637065413L,65414L,65415L,65416L,65417L,65418L,65419L,65420L,65421L,65422L,
8637165423L,65424L,65425L,65426L,65427L,65428L,65429L,65430L,65431L,65432L,
8637265433L,65434L,65435L,65436L,65437L,65438L,65439L,65440L,65441L,65442L,
8637365443L,65444L,65445L,65446L,65447L,65448L,65449L,65450L,65451L,65452L,
8637465453L,65454L,65455L,65456L,65457L,65458L,65459L,65460L,65461L,65462L,
8637565463L,65464L,65465L,65466L,65467L,65468L,65469L,65470L,65471L,65472L,
8637665473L,65474L,65475L,65476L,65477L,65478L,65479L,65480L,65481L,65482L,
8637765483L,65484L,65485L,65486L,65487L,65488L,65489L,65490L,65491L,65492L,
8637865493L,65494L,65495L,65496L,65497L,65498L,65499L,65500L,65501L,65502L,
8637965503L,65504L,65505L,65506L,65507L,65508L,65509L,65510L,65511L,65512L,
8638065513L,65514L,65515L,65516L,65517L,65518L,65519L,65520L,65521L,65522L,
8638165523L,65524L,65525L,65526L,65527L,65528L,65529L,65530L,65531L,65532L,
8638265533L,65534L,65535L,
86383};
86384#endif
86385#line 1 "duk_util_bitdecoder.c"
86386/*
86387 * Bitstream decoder.
86388 */
86389
86390/* include removed: duk_internal.h */
86391
86392/* Decode 'bits' bits from the input stream (bits must be 1...24).
86393 * When reading past bitstream end, zeroes are shifted in. The result
86394 * is signed to match duk_bd_decode_flagged.
86395 */
86396DUK_INTERNAL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
86397 duk_small_int_t shift;
86398 duk_uint32_t mask;
86399 duk_uint32_t tmp;
86400
86401 /* Note: cannot read more than 24 bits without possibly shifting top bits out.
86402 * Fixable, but adds complexity.
86403 */
86404 DUK_ASSERT(bits >= 1 && bits <= 24);
86405
86406 while (ctx->currbits < bits) {
86407#if 0
86408 DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)",
86409 (long) bits, (long) ctx->currbits));
86410#endif
86411 ctx->currval <<= 8;
86412 if (ctx->offset < ctx->length) {
86413 /* If ctx->offset >= ctx->length, we "shift zeroes in"
86414 * instead of croaking.
86415 */
86416 ctx->currval |= ctx->data[ctx->offset++];
86417 }
86418 ctx->currbits += 8;
86419 }
86420#if 0
86421 DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx",
86422 (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval));
86423#endif
86424
86425 /* Extract 'top' bits of currval; note that the extracted bits do not need
86426 * to be cleared, we just ignore them on next round.
86427 */
86428 shift = ctx->currbits - bits;
86429 mask = (1 << bits) - 1;
86430 tmp = (ctx->currval >> shift) & mask;
86431 ctx->currbits = shift; /* remaining */
86432
86433#if 0
86434 DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx",
86435 (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval));
86436#endif
86437
86438 return tmp;
86439}
86440
86441DUK_INTERNAL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
86442 return (duk_small_int_t) duk_bd_decode(ctx, 1);
86443}
86444
86445/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
86446 * default value. Return value is signed so that negative marker value can be
86447 * used by caller as a "not present" value.
86448 */
86449DUK_INTERNAL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
86450 if (duk_bd_decode_flag(ctx)) {
86451 return (duk_int32_t) duk_bd_decode(ctx, bits);
86452 } else {
86453 return def_value;
86454 }
86455}
86456#line 1 "duk_util_bitencoder.c"
86457/*
86458 * Bitstream encoder.
86459 */
86460
86461/* include removed: duk_internal.h */
86462
86463DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
86464 duk_uint8_t tmp;
86465
86466 DUK_ASSERT(ctx != NULL);
86467 DUK_ASSERT(ctx->currbits < 8);
86468
86469 /* This limitation would be fixable but adds unnecessary complexity. */
86470 DUK_ASSERT(bits >= 1 && bits <= 24);
86471
86472 ctx->currval = (ctx->currval << bits) | data;
86473 ctx->currbits += bits;
86474
86475 while (ctx->currbits >= 8) {
86476 if (ctx->offset < ctx->length) {
86477 tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff);
86478 ctx->data[ctx->offset++] = tmp;
86479 } else {
86480 /* If buffer has been exhausted, truncate bitstream */
86481 ctx->truncated = 1;
86482 }
86483
86484 ctx->currbits -= 8;
86485 }
86486}
86487
86488DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
86489 duk_small_int_t npad;
86490
86491 DUK_ASSERT(ctx != NULL);
86492 DUK_ASSERT(ctx->currbits < 8);
86493
86494 npad = (duk_small_int_t) (8 - ctx->currbits);
86495 if (npad > 0) {
86496 duk_be_encode(ctx, 0, npad);
86497 }
86498 DUK_ASSERT(ctx->currbits == 0);
86499}
86500#line 1 "duk_util_bufwriter.c"
86501/*
86502 * Fast buffer writer with spare management.
86503 */
86504
86505/* include removed: duk_internal.h */
86506
86507/*
86508 * Macro support functions (use only macros in calling code)
86509 */
86510
86511DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) {
86512 duk_uint8_t *p;
86513
86514 DUK_ASSERT(thr != NULL);
86515 DUK_ASSERT(bw_ctx != NULL);
86516 DUK_UNREF(thr);
86517
86518 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf);
86519 DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0));
86520 bw_ctx->p = p + curr_offset;
86521 bw_ctx->p_base = p;
86522 bw_ctx->p_limit = p + new_length;
86523}
86524
86525DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) {
86526
86527 DUK_ASSERT(thr != NULL);
86528 DUK_ASSERT(bw_ctx != NULL);
86529 DUK_ASSERT(h_buf != NULL);
86530 DUK_UNREF(thr);
86531
86532 bw_ctx->buf = h_buf;
86533 duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
86534}
86535
86536DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
86537 duk_context *ctx;
86538
86539 DUK_ASSERT(thr != NULL);
86540 DUK_ASSERT(bw_ctx != NULL);
86541 ctx = (duk_context *) thr;
86542
86543 (void) duk_push_dynamic_buffer(ctx, buf_size);
86544 bw_ctx->buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
86545 duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
86546}
86547
86548/* Resize target buffer for requested size. Called by the macro only when the
86549 * fast path test (= there is space) fails.
86550 */
86551DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) {
86552 duk_size_t curr_off;
86553 duk_size_t add_sz;
86554 duk_size_t new_sz;
86555
86556 DUK_ASSERT(thr != NULL);
86557 DUK_ASSERT(bw_ctx != NULL);
86558
86559 /* We could do this operation without caller updating bw_ctx->ptr,
86560 * but by writing it back here we can share code better.
86561 */
86562
86563 curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
86564 add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD;
86565 new_sz = curr_off + sz + add_sz;
86566 if (new_sz < curr_off) {
86567 /* overflow */
86568 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
86569 return NULL; /* not reachable */
86570 }
86571#if 0 /* for manual torture testing: tight allocation, useful with valgrind */
86572 new_sz = curr_off + sz;
86573#endif
86574
86575 /* This is important to ensure dynamic buffer data pointer is not
86576 * NULL (which is possible if buffer size is zero), which in turn
86577 * causes portability issues with e.g. memmove() and memcpy().
86578 */
86579 DUK_ASSERT(new_sz >= 1);
86580
86581 DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)", (long) curr_off, (long) new_sz, (long) add_sz));
86582
86583 duk_hbuffer_resize(thr, bw_ctx->buf, new_sz);
86584 duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz);
86585 return bw_ctx->p;
86586}
86587
86588/* Make buffer compact, matching current written size. */
86589DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) {
86590 duk_size_t len;
86591
86592 DUK_ASSERT(thr != NULL);
86593 DUK_ASSERT(bw_ctx != NULL);
86594 DUK_UNREF(thr);
86595
86596 len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
86597 duk_hbuffer_resize(thr, bw_ctx->buf, len);
86598 duk__bw_update_ptrs(thr, bw_ctx, len, len);
86599}
86600
86601DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
86602 duk_uint8_t *p_base;
86603
86604 DUK_ASSERT(thr != NULL);
86605 DUK_ASSERT(bw != NULL);
86606 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86607 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86608 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86609 DUK_UNREF(thr);
86610
86611 p_base = bw->p_base;
86612 DUK_MEMCPY((void *) bw->p,
86613 (const void *) (p_base + src_off),
86614 (size_t) len);
86615 bw->p += len;
86616}
86617
86618DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
86619 DUK_ASSERT(thr != NULL);
86620 DUK_ASSERT(bw != NULL);
86621 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86622 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86623 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86624 DUK_UNREF(thr);
86625
86626 DUK_BW_ENSURE(thr, bw, len);
86627 duk_bw_write_raw_slice(thr, bw, src_off, len);
86628}
86629
86630DUK_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) {
86631 duk_uint8_t *p_base;
86632 duk_size_t buf_sz, move_sz;
86633
86634 DUK_ASSERT(thr != NULL);
86635 DUK_ASSERT(bw != NULL);
86636 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86637 DUK_ASSERT(buf != NULL);
86638 DUK_UNREF(thr);
86639
86640 p_base = bw->p_base;
86641 buf_sz = bw->p - p_base;
86642 move_sz = buf_sz - dst_off;
86643
86644 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
86645 DUK_MEMMOVE((void *) (p_base + dst_off + len),
86646 (const void *) (p_base + dst_off),
86647 (size_t) move_sz);
86648 DUK_MEMCPY((void *) (p_base + dst_off),
86649 (const void *) buf,
86650 (size_t) len);
86651 bw->p += len;
86652}
86653
86654DUK_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) {
86655 DUK_ASSERT(thr != NULL);
86656 DUK_ASSERT(bw != NULL);
86657 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86658 DUK_ASSERT(buf != NULL);
86659 DUK_UNREF(thr);
86660
86661 DUK_BW_ENSURE(thr, bw, len);
86662 duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
86663}
86664
86665DUK_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) {
86666 duk_uint8_t *p_base;
86667 duk_size_t buf_sz, move_sz;
86668
86669 DUK_ASSERT(thr != NULL);
86670 DUK_ASSERT(bw != NULL);
86671 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86672 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86673 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86674 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86675 DUK_UNREF(thr);
86676
86677 p_base = bw->p_base;
86678
86679 /* Don't support "straddled" source now. */
86680 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
86681
86682 if (dst_off <= src_off) {
86683 /* Target is before source. Source offset is expressed as
86684 * a "before change" offset. Account for the memmove.
86685 */
86686 src_off += len;
86687 }
86688
86689 buf_sz = bw->p - p_base;
86690 move_sz = buf_sz - dst_off;
86691
86692 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
86693 DUK_MEMMOVE((void *) (p_base + dst_off + len),
86694 (const void *) (p_base + dst_off),
86695 (size_t) move_sz);
86696 DUK_MEMCPY((void *) (p_base + dst_off),
86697 (const void *) (p_base + src_off),
86698 (size_t) len);
86699 bw->p += len;
86700}
86701
86702DUK_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) {
86703 DUK_ASSERT(thr != NULL);
86704 DUK_ASSERT(bw != NULL);
86705 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86706 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86707 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86708 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86709 DUK_UNREF(thr);
86710
86711 /* Don't support "straddled" source now. */
86712 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
86713
86714 DUK_BW_ENSURE(thr, bw, len);
86715 duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len);
86716}
86717
86718DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
86719 duk_uint8_t *p_base, *p_dst, *p_src;
86720 duk_size_t buf_sz, move_sz;
86721
86722 DUK_ASSERT(thr != NULL);
86723 DUK_ASSERT(bw != NULL);
86724 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
86725 DUK_UNREF(thr);
86726
86727 p_base = bw->p_base;
86728 buf_sz = bw->p - p_base;
86729 move_sz = buf_sz - off;
86730 p_dst = p_base + off + len;
86731 p_src = p_base + off;
86732 DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz);
86733 return p_src; /* point to start of 'reserved area' */
86734}
86735
86736DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
86737 DUK_ASSERT(thr != NULL);
86738 DUK_ASSERT(bw != NULL);
86739 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
86740 DUK_UNREF(thr);
86741
86742 DUK_BW_ENSURE(thr, bw, len);
86743 return duk_bw_insert_raw_area(thr, bw, off, len);
86744}
86745
86746DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
86747 duk_size_t move_sz;
86748
86749 duk_uint8_t *p_base;
86750 duk_uint8_t *p_src;
86751 duk_uint8_t *p_dst;
86752
86753 DUK_ASSERT(thr != NULL);
86754 DUK_ASSERT(bw != NULL);
86755 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
86756 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86757 DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw));
86758 DUK_UNREF(thr);
86759
86760 p_base = bw->p_base;
86761 p_dst = p_base + off;
86762 p_src = p_dst + len;
86763 move_sz = (duk_size_t) (bw->p - p_src);
86764 DUK_MEMMOVE((void *) p_dst,
86765 (const void *) p_src,
86766 (size_t) move_sz);
86767 bw->p -= len;
86768}
86769
86770/*
86771 * Macro support functions for reading/writing raw data.
86772 *
86773 * These are done using mempcy to ensure they're valid even for unaligned
86774 * reads/writes on platforms where alignment counts. On x86 at least gcc
86775 * is able to compile these into a bswap+mov. "Always inline" is used to
86776 * ensure these macros compile to minimal code.
86777 *
86778 * Not really bufwriter related, but currently used together.
86779 */
86780
86781DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) {
86782 union {
86783 duk_uint8_t b[2];
86784 duk_uint16_t x;
86785 } u;
86786
86787 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2);
86788 u.x = DUK_NTOH16(u.x);
86789 *p += 2;
86790 return u.x;
86791}
86792
86793DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) {
86794 union {
86795 duk_uint8_t b[4];
86796 duk_uint32_t x;
86797 } u;
86798
86799 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
86800 u.x = DUK_NTOH32(u.x);
86801 *p += 4;
86802 return u.x;
86803}
86804
86805DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p) {
86806 duk_double_union du;
86807 union {
86808 duk_uint8_t b[4];
86809 duk_uint32_t x;
86810 } u;
86811
86812 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
86813 u.x = DUK_NTOH32(u.x);
86814 du.ui[DUK_DBL_IDX_UI0] = u.x;
86815 DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4);
86816 u.x = DUK_NTOH32(u.x);
86817 du.ui[DUK_DBL_IDX_UI1] = u.x;
86818 *p += 8;
86819
86820 return du.d;
86821}
86822
86823DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val) {
86824 union {
86825 duk_uint8_t b[2];
86826 duk_uint16_t x;
86827 } u;
86828
86829 u.x = DUK_HTON16(val);
86830 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2);
86831 *p += 2;
86832}
86833
86834DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val) {
86835 union {
86836 duk_uint8_t b[4];
86837 duk_uint32_t x;
86838 } u;
86839
86840 u.x = DUK_HTON32(val);
86841 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
86842 *p += 4;
86843}
86844
86845DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val) {
86846 duk_double_union du;
86847 union {
86848 duk_uint8_t b[4];
86849 duk_uint32_t x;
86850 } u;
86851
86852 du.d = val;
86853 u.x = du.ui[DUK_DBL_IDX_UI0];
86854 u.x = DUK_HTON32(u.x);
86855 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
86856 u.x = du.ui[DUK_DBL_IDX_UI1];
86857 u.x = DUK_HTON32(u.x);
86858 DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4);
86859 *p += 8;
86860}
86861#line 1 "duk_util_hashbytes.c"
86862/*
86863 * Hash function duk_util_hashbytes().
86864 *
86865 * Currently, 32-bit MurmurHash2.
86866 *
86867 * Don't rely on specific hash values; hash function may be endianness
86868 * dependent, for instance.
86869 */
86870
86871/* include removed: duk_internal.h */
86872
86873#if defined(DUK_USE_STRHASH_DENSE)
86874/* 'magic' constants for Murmurhash2 */
86875#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL)
86876#define DUK__MAGIC_R 24
86877
86878DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
86879 duk_uint32_t h = seed ^ ((duk_uint32_t) len);
86880
86881 while (len >= 4) {
86882 /* Portability workaround is required for platforms without
86883 * unaligned access. The replacement code emulates little
86884 * endian access even on big endian architectures, which is
86885 * OK as long as it is consistent for a build.
86886 */
86887#ifdef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
86888 duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
86889#else
86890 duk_uint32_t k = ((duk_uint32_t) data[0]) |
86891 (((duk_uint32_t) data[1]) << 8) |
86892 (((duk_uint32_t) data[2]) << 16) |
86893 (((duk_uint32_t) data[3]) << 24);
86894#endif
86895
86896 k *= DUK__MAGIC_M;
86897 k ^= k >> DUK__MAGIC_R;
86898 k *= DUK__MAGIC_M;
86899 h *= DUK__MAGIC_M;
86900 h ^= k;
86901 data += 4;
86902 len -= 4;
86903 }
86904
86905 switch (len) {
86906 case 3: h ^= data[2] << 16;
86907 case 2: h ^= data[1] << 8;
86908 case 1: h ^= data[0];
86909 h *= DUK__MAGIC_M;
86910 }
86911
86912 h ^= h >> 13;
86913 h *= DUK__MAGIC_M;
86914 h ^= h >> 15;
86915
86916 return h;
86917}
86918#endif /* DUK_USE_STRHASH_DENSE */
86919#line 1 "duk_util_tinyrandom.c"
86920/*
86921 * A tiny random number generator.
86922 *
86923 * Currently used for Math.random().
86924 *
86925 * http://www.woodmann.com/forum/archive/index.php/t-3100.html
86926 */
86927
86928/* include removed: duk_internal.h */
86929
86930#define DUK__UPDATE_RND(rnd) do { \
86931 (rnd) += ((rnd) * (rnd)) | 0x05; \
86932 (rnd) = ((rnd) & 0xffffffffU); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
86933 } while (0)
86934
86935#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */
86936
86937DUK_INTERNAL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n) {
86938 duk_small_int_t i;
86939 duk_uint32_t res = 0;
86940 duk_uint32_t rnd;
86941
86942 rnd = thr->heap->rnd_state;
86943
86944 for (i = 0; i < n; i++) {
86945 DUK__UPDATE_RND(rnd);
86946 res <<= 1;
86947 res += DUK__RND_BIT(rnd);
86948 }
86949
86950 thr->heap->rnd_state = rnd;
86951
86952 return res;
86953}
86954
86955DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
86956 duk_double_t t;
86957 duk_small_int_t n;
86958 duk_uint32_t rnd;
86959
86960 /*
86961 * XXX: could make this a lot faster if we create the double memory
86962 * representation directly. Feasible easily (must be uniform random).
86963 */
86964
86965 rnd = thr->heap->rnd_state;
86966
86967 n = 53; /* enough to cover the whole mantissa */
86968 t = 0.0;
86969
86970 do {
86971 DUK__UPDATE_RND(rnd);
86972 t += DUK__RND_BIT(rnd);
86973 t /= 2.0;
86974 } while (--n);
86975
86976 thr->heap->rnd_state = rnd;
86977
86978 DUK_ASSERT(t >= (duk_double_t) 0.0);
86979 DUK_ASSERT(t < (duk_double_t) 1.0);
86980
86981 return t;
86982}